diff --git a/appcheck/firebase-appcheck-debug-testing/CHANGELOG.md b/appcheck/firebase-appcheck-debug-testing/CHANGELOG.md new file mode 100644 index 00000000000..e9a4b2de744 --- /dev/null +++ b/appcheck/firebase-appcheck-debug-testing/CHANGELOG.md @@ -0,0 +1,41 @@ +# Unreleased + +# 16.1.0 +* [unchanged] Updated to accommodate the release of the updated + [app_check] Kotlin extensions library. + +# 16.0.1 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + +# 16.0.0 +* [changed] [app_check] has exited beta and is now generally available for + use. + +# 16.0.0-beta06 +* [fixed] Fixed a bug in the [app_check] token refresh flow when using a + custom provider. + +# 16.0.0-beta05 +* [changed] Internal improvements. + +# 16.0.0-beta04 +* [changed] Improved error handling logic by minimizing the amount of requests + that are unlikely to succeed. + +* [fixed] Fixed heartbeat reporting. + +# 16.0.0-beta03 +* [changed] Added `X-Android-Package` and `X-Android-Cert` request headers to + [app_check] network calls. + +# 16.0.0-beta02 +* [feature] Added [`getAppCheckToken()`](/docs/reference/android/com/google/firebase/appcheck/FirebaseAppCheck#getAppCheckToken(boolean)), + [`AppCheckTokenListener`](/docs/reference/android/com/google/firebase/appcheck/FirebaseAppCheck.AppCheckListener), + and associated setters and removers for developers to request and observe + changes to the [app_check] token. + +# 16.0.0-beta01 +* [feature] Initial beta release of the [app_check] Debug Testing SDK with + abuse reduction features. + diff --git a/appcheck/firebase-appcheck-debug-testing/gradle.properties b/appcheck/firebase-appcheck-debug-testing/gradle.properties index c763f64467b..0e34974b3c7 100644 --- a/appcheck/firebase-appcheck-debug-testing/gradle.properties +++ b/appcheck/firebase-appcheck-debug-testing/gradle.properties @@ -1,2 +1,2 @@ -version=16.0.2 -latestReleasedVersion=16.0.1 +version=16.0.3 +latestReleasedVersion=16.0.2 diff --git a/appcheck/firebase-appcheck-debug/CHANGELOG.md b/appcheck/firebase-appcheck-debug/CHANGELOG.md new file mode 100644 index 00000000000..b23c1898f40 --- /dev/null +++ b/appcheck/firebase-appcheck-debug/CHANGELOG.md @@ -0,0 +1,41 @@ +# Unreleased + +# 16.1.0 +* [unchanged] Updated to accommodate the release of the updated + [app_check] Kotlin extensions library. + +# 16.0.1 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + +# 16.0.0 +* [changed] [app_check] has exited beta and is now generally available for + use. + +# 16.0.0-beta06 +* [fixed] Fixed a bug in the [app_check] token refresh flow when using a + custom provider. + +# 16.0.0-beta05 +* [changed] Internal improvements. + +# 16.0.0-beta04 +* [changed] Improved error handling logic by minimizing the amount of requests + that are unlikely to succeed. + +* [fixed] Fixed heartbeat reporting. + +# 16.0.0-beta03 +* [changed] Added `X-Android-Package` and `X-Android-Cert` request headers to + [app_check] network calls. + +# 16.0.0-beta02 +* [feature] Added [`getAppCheckToken()`](/docs/reference/android/com/google/firebase/appcheck/FirebaseAppCheck#getAppCheckToken(boolean)), + [`AppCheckTokenListener`](/docs/reference/android/com/google/firebase/appcheck/FirebaseAppCheck.AppCheckListener), + and associated setters and removers for developers to request and observe + changes to the [app_check] token. + +# 16.0.0-beta01 +* [feature] Initial beta release of the [app_check] Debug SDK with abuse + reduction features. + diff --git a/appcheck/firebase-appcheck-debug/gradle.properties b/appcheck/firebase-appcheck-debug/gradle.properties index c763f64467b..0e34974b3c7 100644 --- a/appcheck/firebase-appcheck-debug/gradle.properties +++ b/appcheck/firebase-appcheck-debug/gradle.properties @@ -1,2 +1,2 @@ -version=16.0.2 -latestReleasedVersion=16.0.1 +version=16.0.3 +latestReleasedVersion=16.0.2 diff --git a/appcheck/firebase-appcheck-debug/src/main/java/com/google/firebase/appcheck/debug/FirebaseAppCheckDebugRegistrar.java b/appcheck/firebase-appcheck-debug/src/main/java/com/google/firebase/appcheck/debug/FirebaseAppCheckDebugRegistrar.java index 2b79ba545b8..b2a525f161b 100644 --- a/appcheck/firebase-appcheck-debug/src/main/java/com/google/firebase/appcheck/debug/FirebaseAppCheckDebugRegistrar.java +++ b/appcheck/firebase-appcheck-debug/src/main/java/com/google/firebase/appcheck/debug/FirebaseAppCheckDebugRegistrar.java @@ -29,10 +29,10 @@ */ @KeepForSdk public class FirebaseAppCheckDebugRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-app-check-debug"; @Override public List> getComponents() { - return Arrays.asList( - LibraryVersionComponent.create("fire-app-check-debug", BuildConfig.VERSION_NAME)); + return Arrays.asList(LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/appcheck/firebase-appcheck-interop/gradle.properties b/appcheck/firebase-appcheck-interop/gradle.properties index c763f64467b..0e34974b3c7 100644 --- a/appcheck/firebase-appcheck-interop/gradle.properties +++ b/appcheck/firebase-appcheck-interop/gradle.properties @@ -1,2 +1,2 @@ -version=16.0.2 -latestReleasedVersion=16.0.1 +version=16.0.3 +latestReleasedVersion=16.0.2 diff --git a/appcheck/firebase-appcheck-playintegrity/CHANGELOG.md b/appcheck/firebase-appcheck-playintegrity/CHANGELOG.md new file mode 100644 index 00000000000..bdea5a89161 --- /dev/null +++ b/appcheck/firebase-appcheck-playintegrity/CHANGELOG.md @@ -0,0 +1,15 @@ +# Unreleased + +# 16.1.0 +* [unchanged] Updated to accommodate the release of the updated + [app_check] Kotlin extensions library. + +# 16.0.1 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + +# 16.0.0 +* [feature] Added support for + [Play Integrity](https://developer.android.com/google/play/integrity) as an + attestation provider. + diff --git a/appcheck/firebase-appcheck-playintegrity/gradle.properties b/appcheck/firebase-appcheck-playintegrity/gradle.properties index c763f64467b..0e34974b3c7 100644 --- a/appcheck/firebase-appcheck-playintegrity/gradle.properties +++ b/appcheck/firebase-appcheck-playintegrity/gradle.properties @@ -1,2 +1,2 @@ -version=16.0.2 -latestReleasedVersion=16.0.1 +version=16.0.3 +latestReleasedVersion=16.0.2 diff --git a/appcheck/firebase-appcheck-playintegrity/src/main/java/com/google/firebase/appcheck/playintegrity/FirebaseAppCheckPlayIntegrityRegistrar.java b/appcheck/firebase-appcheck-playintegrity/src/main/java/com/google/firebase/appcheck/playintegrity/FirebaseAppCheckPlayIntegrityRegistrar.java index d71af7a7a88..b1af71a1651 100644 --- a/appcheck/firebase-appcheck-playintegrity/src/main/java/com/google/firebase/appcheck/playintegrity/FirebaseAppCheckPlayIntegrityRegistrar.java +++ b/appcheck/firebase-appcheck-playintegrity/src/main/java/com/google/firebase/appcheck/playintegrity/FirebaseAppCheckPlayIntegrityRegistrar.java @@ -29,10 +29,10 @@ */ @KeepForSdk public class FirebaseAppCheckPlayIntegrityRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-app-check-play-integrity"; @Override public List> getComponents() { - return Arrays.asList( - LibraryVersionComponent.create("fire-app-check-play-integrity", BuildConfig.VERSION_NAME)); + return Arrays.asList(LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/appcheck/firebase-appcheck-safetynet/CHANGELOG.md b/appcheck/firebase-appcheck-safetynet/CHANGELOG.md new file mode 100644 index 00000000000..39e56b1e276 --- /dev/null +++ b/appcheck/firebase-appcheck-safetynet/CHANGELOG.md @@ -0,0 +1,41 @@ +# Unreleased + +# 16.1.0 +* [unchanged] Updated to accommodate the release of the updated + [app_check] Kotlin extensions library. + +# 16.0.1 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + +# 16.0.0 +* [changed] [app_check] has exited beta and is now generally available for + use. + +# 16.0.0-beta06 +* [fixed] Fixed a bug in the [app_check] token refresh flow when using a + custom provider. + +# 16.0.0-beta05 +* [changed] Internal improvements. + +# 16.0.0-beta04 +* [changed] Improved error handling logic by minimizing the amount of requests + that are unlikely to succeed. + +* [fixed] Fixed heartbeat reporting. + +# 16.0.0-beta03 +* [changed] Added `X-Android-Package` and `X-Android-Cert` request headers to + [app_check] network calls. + +# 16.0.0-beta02 +* [feature] Added [`getAppCheckToken()`](/docs/reference/android/com/google/firebase/appcheck/FirebaseAppCheck#getAppCheckToken(boolean)), + [`AppCheckTokenListener`](/docs/reference/android/com/google/firebase/appcheck/FirebaseAppCheck.AppCheckListener), + and associated setters and removers for developers to request and observe + changes to the [app_check] token. + +# 16.0.0-beta01 +* [feature] Initial beta release of the [app_check] SafetyNet SDK with abuse + reduction features. + diff --git a/appcheck/firebase-appcheck-safetynet/gradle.properties b/appcheck/firebase-appcheck-safetynet/gradle.properties index 3f52c6a64ab..0e34974b3c7 100644 --- a/appcheck/firebase-appcheck-safetynet/gradle.properties +++ b/appcheck/firebase-appcheck-safetynet/gradle.properties @@ -1 +1,2 @@ -version=16.0.2 +version=16.0.3 +latestReleasedVersion=16.0.2 diff --git a/appcheck/firebase-appcheck-safetynet/src/main/java/com/google/firebase/appcheck/safetynet/FirebaseAppCheckSafetyNetRegistrar.java b/appcheck/firebase-appcheck-safetynet/src/main/java/com/google/firebase/appcheck/safetynet/FirebaseAppCheckSafetyNetRegistrar.java index b922c56f17e..9e7080fda7c 100644 --- a/appcheck/firebase-appcheck-safetynet/src/main/java/com/google/firebase/appcheck/safetynet/FirebaseAppCheckSafetyNetRegistrar.java +++ b/appcheck/firebase-appcheck-safetynet/src/main/java/com/google/firebase/appcheck/safetynet/FirebaseAppCheckSafetyNetRegistrar.java @@ -29,10 +29,10 @@ */ @KeepForSdk public class FirebaseAppCheckSafetyNetRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-app-check-safety-net"; @Override public List> getComponents() { - return Arrays.asList( - LibraryVersionComponent.create("fire-app-check-safety-net", BuildConfig.VERSION_NAME)); + return Arrays.asList(LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/appcheck/firebase-appcheck-safetynet/src/main/java/com/google/firebase/appcheck/safetynet/SafetyNetAppCheckProviderFactory.java b/appcheck/firebase-appcheck-safetynet/src/main/java/com/google/firebase/appcheck/safetynet/SafetyNetAppCheckProviderFactory.java index f6b2e019bed..7ddc9889ce8 100644 --- a/appcheck/firebase-appcheck-safetynet/src/main/java/com/google/firebase/appcheck/safetynet/SafetyNetAppCheckProviderFactory.java +++ b/appcheck/firebase-appcheck-safetynet/src/main/java/com/google/firebase/appcheck/safetynet/SafetyNetAppCheckProviderFactory.java @@ -23,7 +23,10 @@ /** * Implementation of an {@link AppCheckProviderFactory} that builds {@link * SafetyNetAppCheckProvider}s. This is the default implementation. + * + * @deprecated Use {@code PlayIntegrityAppCheckProviderFactory} instead. */ +@Deprecated public class SafetyNetAppCheckProviderFactory implements AppCheckProviderFactory { private static final SafetyNetAppCheckProviderFactory instance = @@ -34,7 +37,10 @@ private SafetyNetAppCheckProviderFactory() {} /** * Gets an instance of this class for installation into a {@link * com.google.firebase.appcheck.FirebaseAppCheck} instance. + * + * @deprecated Use {@code PlayIntegrityAppCheckProviderFactory#getInstance} instead. */ + @Deprecated @NonNull public static SafetyNetAppCheckProviderFactory getInstance() { return instance; diff --git a/appcheck/firebase-appcheck/CHANGELOG.md b/appcheck/firebase-appcheck/CHANGELOG.md new file mode 100644 index 00000000000..e66859e9abe --- /dev/null +++ b/appcheck/firebase-appcheck/CHANGELOG.md @@ -0,0 +1,59 @@ +# Unreleased + +# 16.1.0 +* [unchanged] Updated to accommodate the release of the updated + [app_check] Kotlin extensions library. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-appcheck` library. The Kotlin extensions library has the following +additional updates: + +* [feature] Firebase now supports Kotlin coroutines. + With this release, we added + [`kotlinx-coroutines-play-services`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-play-services/){: .external} + to `firebase-appcheck-ktx` as a transitive dependency, which exposes the + `Task.await()` suspend function to convert a + [`Task`](https://developers.google.com/android/guides/tasks) into a Kotlin + coroutine. + +# 16.0.1 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + +# 16.0.0 +* [changed] [app_check] has exited beta and is now generally available for + use. + +* [feature] Added support for + [Play Integrity](https://developer.android.com/google/play/integrity) as an + attestation provider. + +# 16.0.0-beta06 +* [fixed] Fixed a bug in the [app_check] token refresh flow when using a + custom provider. + +# 16.0.0-beta05 +* [changed] Internal improvements. + +# 16.0.0-beta04 +* [changed] Improved error handling logic by minimizing the amount of requests + that are unlikely to succeed. + +* [fixed] Fixed heartbeat reporting. + +# 16.0.0-beta03 +* [changed] Added `X-Android-Package` and `X-Android-Cert` request headers to + [app_check] network calls. + +# 16.0.0-beta02 +* [feature] Added [`getAppCheckToken()`](/docs/reference/android/com/google/firebase/appcheck/FirebaseAppCheck#getAppCheckToken(boolean)), + [`AppCheckTokenListener`](/docs/reference/android/com/google/firebase/appcheck/FirebaseAppCheck.AppCheckListener), + and associated setters and removers for developers to request and observe + changes to the [app_check] token. + +# 16.0.0-beta01 +* [feature] Initial beta release of the [app_check] SDK with abuse reduction + features. + diff --git a/appcheck/firebase-appcheck/firebase-appcheck.gradle b/appcheck/firebase-appcheck/firebase-appcheck.gradle index 3f04fff97ad..6ed2202dd30 100644 --- a/appcheck/firebase-appcheck/firebase-appcheck.gradle +++ b/appcheck/firebase-appcheck/firebase-appcheck.gradle @@ -56,4 +56,14 @@ dependencies { testImplementation "com.google.truth:truth:$googleTruthVersion" testImplementation 'androidx.test:core:1.2.0' testImplementation 'androidx.test:rules:1.2.0' + + androidTestImplementation project(':appcheck:firebase-appcheck') + androidTestImplementation project(':integ-testing') + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation "com.google.truth:truth:$googleTruthVersion" + androidTestImplementation 'junit:junit:4.12' + androidTestImplementation "androidx.annotation:annotation:1.0.0" + androidTestImplementation 'org.mockito:mockito-core:2.25.0' + androidTestImplementation 'org.mockito:mockito-inline:2.25.0' } diff --git a/appcheck/firebase-appcheck/gradle.properties b/appcheck/firebase-appcheck/gradle.properties index c763f64467b..0e34974b3c7 100644 --- a/appcheck/firebase-appcheck/gradle.properties +++ b/appcheck/firebase-appcheck/gradle.properties @@ -1,2 +1,2 @@ -version=16.0.2 -latestReleasedVersion=16.0.1 +version=16.0.3 +latestReleasedVersion=16.0.2 diff --git a/health-metrics/macrobenchmark/template/benchmark/src/androidTest/AndroidManifest.xml b/appcheck/firebase-appcheck/src/androidTest/java/AndroidManifest.xml similarity index 70% rename from health-metrics/macrobenchmark/template/benchmark/src/androidTest/AndroidManifest.xml rename to appcheck/firebase-appcheck/src/androidTest/java/AndroidManifest.xml index a3d4dd73e80..688d908c063 100644 --- a/health-metrics/macrobenchmark/template/benchmark/src/androidTest/AndroidManifest.xml +++ b/appcheck/firebase-appcheck/src/androidTest/java/AndroidManifest.xml @@ -1,5 +1,5 @@ - + @@ -14,11 +14,13 @@ + package="com.google.firebase.appcheck"> - + + + + diff --git a/appcheck/firebase-appcheck/src/androidTest/java/com/google/firebase/appcheck/StrictModeTest.java b/appcheck/firebase-appcheck/src/androidTest/java/com/google/firebase/appcheck/StrictModeTest.java new file mode 100644 index 00000000000..adacf695279 --- /dev/null +++ b/appcheck/firebase-appcheck/src/androidTest/java/com/google/firebase/appcheck/StrictModeTest.java @@ -0,0 +1,49 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.appcheck; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import com.google.firebase.appcheck.interop.InternalAppCheckTokenProvider; +import com.google.firebase.testing.integ.StrictModeRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class StrictModeTest { + + @Rule public StrictModeRule strictMode = new StrictModeRule(); + + @Test + public void initializingFirebaseAppcheck_shouldNotViolateStrictMode() { + strictMode.runOnMainThread( + () -> { + FirebaseApp app = + FirebaseApp.initializeApp( + ApplicationProvider.getApplicationContext(), + new FirebaseOptions.Builder() + .setApiKey("api") + .setProjectId("123") + .setApplicationId("appId") + .build(), + "hello"); + app.get(FirebaseAppCheck.class); + app.get(InternalAppCheckTokenProvider.class); + }); + } +} diff --git a/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/FirebaseAppCheckRegistrar.java b/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/FirebaseAppCheckRegistrar.java index e1ea851563b..8a52acdf20a 100644 --- a/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/FirebaseAppCheckRegistrar.java +++ b/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/FirebaseAppCheckRegistrar.java @@ -35,11 +35,13 @@ */ @KeepForSdk public class FirebaseAppCheckRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-app-check"; @Override public List> getComponents() { return Arrays.asList( Component.builder(FirebaseAppCheck.class, (InternalAppCheckTokenProvider.class)) + .name(LIBRARY_NAME) .add(Dependency.required(FirebaseApp.class)) .add(Dependency.optionalProvider(HeartBeatController.class)) .factory( @@ -50,6 +52,6 @@ public List> getComponents() { .alwaysEager() .build(), HeartBeatConsumerComponent.create(), - LibraryVersionComponent.create("fire-app-check", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheck.java b/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheck.java index 087d10b9868..769bd1048d3 100644 --- a/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheck.java +++ b/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheck.java @@ -21,6 +21,7 @@ import androidx.annotation.VisibleForTesting; import com.google.android.gms.tasks.Continuation; import com.google.android.gms.tasks.Task; +import com.google.android.gms.tasks.TaskCompletionSource; import com.google.android.gms.tasks.Tasks; import com.google.firebase.FirebaseApp; import com.google.firebase.FirebaseException; @@ -35,6 +36,8 @@ import com.google.firebase.inject.Provider; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; public class DefaultFirebaseAppCheck extends FirebaseAppCheck { @@ -46,6 +49,8 @@ public class DefaultFirebaseAppCheck extends FirebaseAppCheck { private final List appCheckListenerList; private final StorageHelper storageHelper; private final TokenRefreshManager tokenRefreshManager; + private final ExecutorService backgroundExecutor; + private final Task retrieveStoredTokenTask; private final Clock clock; private AppCheckProviderFactory appCheckProviderFactory; @@ -55,6 +60,17 @@ public class DefaultFirebaseAppCheck extends FirebaseAppCheck { public DefaultFirebaseAppCheck( @NonNull FirebaseApp firebaseApp, @NonNull Provider heartBeatController) { + this( + checkNotNull(firebaseApp), + checkNotNull(heartBeatController), + Executors.newCachedThreadPool()); + } + + @VisibleForTesting + DefaultFirebaseAppCheck( + @NonNull FirebaseApp firebaseApp, + @NonNull Provider heartBeatController, + @NonNull ExecutorService backgroundExecutor) { checkNotNull(firebaseApp); checkNotNull(heartBeatController); this.firebaseApp = firebaseApp; @@ -65,8 +81,22 @@ public DefaultFirebaseAppCheck( new StorageHelper(firebaseApp.getApplicationContext(), firebaseApp.getPersistenceKey()); this.tokenRefreshManager = new TokenRefreshManager(firebaseApp.getApplicationContext(), /* firebaseAppCheck= */ this); + this.backgroundExecutor = backgroundExecutor; + this.retrieveStoredTokenTask = retrieveStoredAppCheckTokenInBackground(backgroundExecutor); this.clock = new Clock.DefaultClock(); - setCachedToken(storageHelper.retrieveAppCheckToken()); + } + + private Task retrieveStoredAppCheckTokenInBackground(@NonNull ExecutorService executor) { + TaskCompletionSource taskCompletionSource = new TaskCompletionSource<>(); + executor.execute( + () -> { + AppCheckToken token = storageHelper.retrieveAppCheckToken(); + if (token != null) { + setCachedToken(token); + } + taskCompletionSource.setResult(null); + }); + return taskCompletionSource.getTask(); } @Override @@ -146,44 +176,50 @@ public void removeAppCheckListener(@NonNull AppCheckListener listener) { @NonNull @Override public Task getToken(boolean forceRefresh) { - if (!forceRefresh && hasValidToken()) { - return Tasks.forResult(DefaultAppCheckTokenResult.constructFromAppCheckToken(cachedToken)); - } - if (appCheckProvider == null) { - return Tasks.forResult( - DefaultAppCheckTokenResult.constructFromError( - new FirebaseException("No AppCheckProvider installed."))); - } - // TODO: Cache the in-flight task. - return fetchTokenFromProvider() - .continueWithTask( - new Continuation>() { - @Override - public Task then(@NonNull Task task) { - if (task.isSuccessful()) { - return Tasks.forResult( - DefaultAppCheckTokenResult.constructFromAppCheckToken(task.getResult())); - } - // If the token exchange failed, return a dummy token for integrators to attach in - // their headers. - return Tasks.forResult( - DefaultAppCheckTokenResult.constructFromError( - new FirebaseException( - task.getException().getMessage(), task.getException()))); - } - }); + return retrieveStoredTokenTask.continueWithTask( + unused -> { + if (!forceRefresh && hasValidToken()) { + return Tasks.forResult( + DefaultAppCheckTokenResult.constructFromAppCheckToken(cachedToken)); + } + if (appCheckProvider == null) { + return Tasks.forResult( + DefaultAppCheckTokenResult.constructFromError( + new FirebaseException("No AppCheckProvider installed."))); + } + // TODO: Cache the in-flight task. + return fetchTokenFromProvider() + .continueWithTask( + appCheckTokenTask -> { + if (appCheckTokenTask.isSuccessful()) { + return Tasks.forResult( + DefaultAppCheckTokenResult.constructFromAppCheckToken( + appCheckTokenTask.getResult())); + } + // If the token exchange failed, return a dummy token for integrators to attach + // in their headers. + return Tasks.forResult( + DefaultAppCheckTokenResult.constructFromError( + new FirebaseException( + appCheckTokenTask.getException().getMessage(), + appCheckTokenTask.getException()))); + }); + }); } @NonNull @Override public Task getAppCheckToken(boolean forceRefresh) { - if (!forceRefresh && hasValidToken()) { - return Tasks.forResult(cachedToken); - } - if (appCheckProvider == null) { - return Tasks.forException(new FirebaseException("No AppCheckProvider installed.")); - } - return fetchTokenFromProvider(); + return retrieveStoredTokenTask.continueWithTask( + unused -> { + if (!forceRefresh && hasValidToken()) { + return Tasks.forResult(cachedToken); + } + if (appCheckProvider == null) { + return Tasks.forException(new FirebaseException("No AppCheckProvider installed.")); + } + return fetchTokenFromProvider(); + }); } /** Fetches an {@link AppCheckToken} via the installed {@link AppCheckProvider}. */ @@ -227,7 +263,7 @@ void setCachedToken(@NonNull AppCheckToken token) { * well as the in-memory cached {@link AppCheckToken}. */ private void updateStoredToken(@NonNull AppCheckToken token) { - storageHelper.saveAppCheckToken(token); + backgroundExecutor.execute(() -> storageHelper.saveAppCheckToken(token)); setCachedToken(token); tokenRefreshManager.maybeScheduleTokenRefresh(token); diff --git a/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/internal/StorageHelper.java b/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/internal/StorageHelper.java index 5537b636cf9..ae821de0d39 100644 --- a/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/internal/StorageHelper.java +++ b/appcheck/firebase-appcheck/src/main/java/com/google/firebase/appcheck/internal/StorageHelper.java @@ -24,6 +24,7 @@ import androidx.annotation.VisibleForTesting; import com.google.firebase.appcheck.AppCheckToken; import com.google.firebase.appcheck.internal.util.Logger; +import com.google.firebase.components.Lazy; /** * Internal class used to persist {@link com.google.firebase.appcheck.AppCheckToken}s. Uses {@link @@ -47,24 +48,27 @@ enum TokenType { UNKNOWN_APP_CHECK_TOKEN } - private SharedPreferences sharedPreferences; + private Lazy sharedPreferences; public StorageHelper(@NonNull Context context, @NonNull String persistenceKey) { checkNotNull(context); checkNotEmpty(persistenceKey); String prefsName = String.format(PREFS_TEMPLATE, persistenceKey); - this.sharedPreferences = context.getSharedPreferences(prefsName, Context.MODE_PRIVATE); + this.sharedPreferences = + new Lazy(() -> context.getSharedPreferences(prefsName, Context.MODE_PRIVATE)); } public void saveAppCheckToken(@NonNull AppCheckToken appCheckToken) { if (appCheckToken instanceof DefaultAppCheckToken) { sharedPreferences + .get() .edit() .putString(TOKEN_KEY, ((DefaultAppCheckToken) appCheckToken).serializeTokenToString()) .putString(TOKEN_TYPE_KEY, TokenType.DEFAULT_APP_CHECK_TOKEN.name()) .apply(); } else { sharedPreferences + .get() .edit() .putString(TOKEN_KEY, appCheckToken.getToken()) .putString(TOKEN_TYPE_KEY, TokenType.UNKNOWN_APP_CHECK_TOKEN.name()) @@ -74,8 +78,8 @@ public void saveAppCheckToken(@NonNull AppCheckToken appCheckToken) { @Nullable public AppCheckToken retrieveAppCheckToken() { - String tokenType = sharedPreferences.getString(TOKEN_TYPE_KEY, null); - String serializedToken = sharedPreferences.getString(TOKEN_KEY, null); + String tokenType = sharedPreferences.get().getString(TOKEN_TYPE_KEY, null); + String serializedToken = sharedPreferences.get().getString(TOKEN_KEY, null); if (tokenType == null || serializedToken == null) { return null; } @@ -101,6 +105,6 @@ public AppCheckToken retrieveAppCheckToken() { } void clearSharedPrefs() { - sharedPreferences.edit().remove(TOKEN_KEY).remove(TOKEN_TYPE_KEY).apply(); + sharedPreferences.get().edit().remove(TOKEN_KEY).remove(TOKEN_TYPE_KEY).apply(); } } diff --git a/appcheck/firebase-appcheck/src/test/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheckTest.java b/appcheck/firebase-appcheck/src/test/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheckTest.java index 320dbd9d1c2..95330db0ed4 100644 --- a/appcheck/firebase-appcheck/src/test/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheckTest.java +++ b/appcheck/firebase-appcheck/src/test/java/com/google/firebase/appcheck/internal/DefaultFirebaseAppCheckTest.java @@ -24,6 +24,7 @@ import androidx.test.core.app.ApplicationProvider; import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.Tasks; +import com.google.common.util.concurrent.MoreExecutors; import com.google.firebase.FirebaseApp; import com.google.firebase.appcheck.AppCheckProvider; import com.google.firebase.appcheck.AppCheckProviderFactory; @@ -74,7 +75,10 @@ public void setup() { when(mockAppCheckProvider.getToken()).thenReturn(Tasks.forResult(validDefaultAppCheckToken)); defaultFirebaseAppCheck = - new DefaultFirebaseAppCheck(mockFirebaseApp, () -> mockHeartBeatController); + new DefaultFirebaseAppCheck( + mockFirebaseApp, + () -> mockHeartBeatController, + MoreExecutors.newDirectExecutorService()); } @Test diff --git a/build.gradle b/build.gradle index af65e9c4bce..30208819267 100644 --- a/build.gradle +++ b/build.gradle @@ -17,6 +17,8 @@ import com.google.firebase.gradle.MultiProjectReleasePlugin buildscript { ext.kotlinVersion = '1.7.10' + ext.coroutinesVersion = '1.6.4' + repositories { google() mavenCentral() diff --git a/buildSrc/src/main/java/com/google/firebase/gradle/bomgenerator/BomGeneratorTask.java b/buildSrc/src/main/java/com/google/firebase/gradle/bomgenerator/BomGeneratorTask.java index 7ac7db9fc10..56589e10f1e 100644 --- a/buildSrc/src/main/java/com/google/firebase/gradle/bomgenerator/BomGeneratorTask.java +++ b/buildSrc/src/main/java/com/google/firebase/gradle/bomgenerator/BomGeneratorTask.java @@ -54,6 +54,7 @@ public class BomGeneratorTask extends DefaultTask { "com.google.firebase:firebase-analytics-ktx", "com.google.firebase:firebase-appcheck-debug", "com.google.firebase:firebase-appcheck-debug-testing", + "com.google.firebase:firebase-appcheck-ktx", "com.google.firebase:firebase-appcheck-playintegrity", "com.google.firebase:firebase-appcheck-safetynet", "com.google.firebase:firebase-appcheck", diff --git a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/DackkaGenerationTask.kt b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/DackkaGenerationTask.kt index 13b76013813..be77a4ef3aa 100644 --- a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/DackkaGenerationTask.kt +++ b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/DackkaGenerationTask.kt @@ -3,6 +3,7 @@ package com.google.firebase.gradle.plugins import java.io.File import javax.inject.Inject import org.gradle.api.DefaultTask +import org.gradle.api.file.FileCollection import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.provider.SetProperty @@ -27,8 +28,7 @@ import org.json.JSONObject * * @property dackkaJarFile a [File] of the Dackka fat jar * @property dependencies a list of all dependent jars (the classpath) - * @property kotlinSources a list of kotlin source roots - * @property javaSources a list of java source roots + * @property sources a list of source roots * @property suppressedFiles a list of files to exclude from documentation * @property outputDirectory where to store the generated files */ @@ -38,15 +38,11 @@ abstract class GenerateDocumentationTaskExtension : DefaultTask() { abstract val dackkaJarFile: Property @get:[InputFiles Classpath] - abstract val dependencies: ListProperty + abstract val dependencies: Property @get:InputFiles @get:PathSensitive(PathSensitivity.RELATIVE) - abstract val kotlinSources: ListProperty - - @get:InputFiles - @get:PathSensitive(PathSensitivity.RELATIVE) - abstract val javaSources: ListProperty + abstract val sources: ListProperty @get:InputFiles @get:PathSensitive(PathSensitivity.RELATIVE) @@ -105,7 +101,7 @@ abstract class GenerateDocumentationTask @Inject constructor( "scopeId" to "androidx", "sourceSetName" to "main" ), - "sourceRoots" to kotlinSources.get().map { it.path } + javaSources.get().map { it.path }, + "sourceRoots" to sources.get().map { it.path }, "classpath" to dependencies.get().map { it.path }, "documentedVisibilities" to listOf("PUBLIC", "PROTECTED"), "skipEmptyPackages" to "true", diff --git a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/DackkaPlugin.kt b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/DackkaPlugin.kt index b274ca52b76..a7606f40a66 100644 --- a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/DackkaPlugin.kt +++ b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/DackkaPlugin.kt @@ -5,9 +5,11 @@ import com.android.build.gradle.LibraryExtension import java.io.File import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.Task import org.gradle.api.provider.Provider import org.gradle.api.tasks.Copy import org.gradle.api.tasks.Delete +import org.gradle.api.tasks.TaskProvider import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.register @@ -90,8 +92,9 @@ tasks above). While we do not currently offer any configuration for the Dackka plugin, this could change in the future as needed. Currently, the DackkaPlugin provides sensible defaults to output directories, package lists, and so forth. -The DackkaPlugin also provides three extra tasks: +The DackkaPlugin also provides four extra tasks: [cleanDackkaDocumentation][registerCleanDackkaDocumentation], +[separateJavadocAndKotlinDoc][registerSeparateJavadocAndKotlinDoc] [copyJavaDocToCommonDirectory][registerCopyJavaDocToCommonDirectoryTask] and [copyKotlinDocToCommonDirectory][registerCopyKotlinDocToCommonDirectoryTask]. @@ -100,6 +103,9 @@ the output of Dackka. This is useful when testing Dackka outputs itself- and shouldn't be apart of the normal flow. The reasoning is that it would otherwise invalidate the gradle cache. +_separateJavadocAndKotlinDoc_ copies the Javadoc and Kotlindoc directories from Dackka into +their own subdirectories- for easy and consistent differentiation. + _copyJavaDocToCommonDirectory_ copies the JavaDoc variant of the Dackka output for each sdk, and pastes it in a common directory under the root project's build directory. This makes it easier to zip the doc files for staging. @@ -119,23 +125,30 @@ abstract class DackkaPlugin : Plugin { registerCleanDackkaDocumentation(project) project.afterEvaluate { if (shouldWePublish(project)) { - val generateDocumentation = registerGenerateDackkaDocumentationTask(project) - val outputDirectory = generateDocumentation.flatMap { it.outputDirectory } - val firesiteTransform = registerFiresiteTransformTask(project, outputDirectory) - val copyJavaDocToCommonDirectory = registerCopyJavaDocToCommonDirectoryTask(project, outputDirectory) - val copyKotlinDocToCommonDirectory = registerCopyKotlinDocToCommonDirectoryTask(project, outputDirectory) + val dackkaOutputDirectory = project.provider { fileFromBuildDir("dackkaRawOutput") } + val separatedFilesDirectory = project.provider { fileFromBuildDir("dackkaSeparatedFiles") } + val transformedDackkaFilesDirectory = project.provider { fileFromBuildDir("dackkaTransformedFiles") } + + val generateDocumentation = registerGenerateDackkaDocumentationTask(project, dackkaOutputDirectory) + val separateJavadocAndKotlinDoc = registerSeparateJavadocAndKotlinDoc(project, dackkaOutputDirectory, separatedFilesDirectory) + val firesiteTransform = registerFiresiteTransformTask(project, separatedFilesDirectory, transformedDackkaFilesDirectory) + val copyJavaDocToCommonDirectory = registerCopyJavaDocToCommonDirectoryTask(project, transformedDackkaFilesDirectory) + val copyKotlinDocToCommonDirectory = registerCopyKotlinDocToCommonDirectoryTask(project, transformedDackkaFilesDirectory) project.tasks.register("kotlindoc") { group = "documentation" dependsOn( generateDocumentation, + separateJavadocAndKotlinDoc, firesiteTransform, copyJavaDocToCommonDirectory, copyKotlinDocToCommonDirectory ) } } else { - project.tasks.register("kotlindoc") + project.tasks.register("kotlindoc") { + group = "documentation" + } } } } @@ -157,7 +170,10 @@ abstract class DackkaPlugin : Plugin { } // TODO(b/243324828): Refactor when fixed, so we no longer need stubs - private fun registerGenerateDackkaDocumentationTask(project: Project): Provider { + private fun registerGenerateDackkaDocumentationTask( + project: Project, + targetDirectory: Provider + ): Provider { val docStubs = project.tasks.register("docStubsForDackkaInput") val docsTask = project.tasks.register("generateDackkaDocumentation") with(project.extensions.getByType()) { @@ -167,31 +183,29 @@ abstract class DackkaPlugin : Plugin { val classpath = compileConfiguration.getJars() + project.javadocConfig.getJars() + project.files(bootClasspath) - val sourcesForJava = sourceSets.flatMap { + val sourceDirectories = sourceSets.flatMap { it.javaDirectories.map { it.absoluteFile } } docStubs.configure { classPath = classpath - sources.set(project.provider { sourcesForJava }) + sources.set(project.provider { sourceDirectories }) } docsTask.configure { - clientName.set(project.firebaseConfigValue { artifactId }) - // this will become useful with the agp upgrade, as they're separate in 7.x+ - val sourcesForKotlin = emptyList() + if (!isKotlin) dependsOn(docStubs) + val packageLists = fetchPackageLists(project) - if (!isKotlin) dependsOn(docStubs) - val excludedFiles = if (!isKotlin) projectSpecificSuppressedFiles(project) else emptyList() - val fixedJavaSources = if (!isKotlin) listOf(project.docStubs) else sourcesForJava + val excludedFiles = projectSpecificSuppressedFiles(project) + val fixedSourceDirectories = if (!isKotlin) listOf(project.docStubs) else sourceDirectories - javaSources.set(fixedJavaSources) + sources.set(fixedSourceDirectories + projectSpecificSources(project)) suppressedFiles.set(excludedFiles) packageListFiles.set(packageLists) - kotlinSources.set(sourcesForKotlin) dependencies.set(classpath) + outputDirectory.set(targetDirectory) applyCommonConfigurations() } @@ -206,11 +220,20 @@ abstract class DackkaPlugin : Plugin { include("**/package-list") }.toList() + // TODO(b/243534168): Remove when fixed + private fun projectSpecificSources(project: Project) = + when (project.name) { + "firebase-common" -> { + project.project(":firebase-firestore").files("src/main/java/com/google/firebase").toList() + } + else -> emptyList() + } + // TODO(b/243534168): Remove when fixed private fun projectSpecificSuppressedFiles(project: Project): List = when (project.name) { "firebase-common" -> { - project.files("${project.docStubs}/com/google/firebase/firestore").toList() + project.project(":firebase-firestore").files("src/main/java/com/google/firebase/firestore").toList() } "firebase-firestore" -> { project.files("${project.docStubs}/com/google/firebase/Timestamp.java").toList() @@ -222,20 +245,73 @@ abstract class DackkaPlugin : Plugin { dependsOnAndMustRunAfter("createFullJarRelease") val dackkaFile = project.provider { project.dackkaConfig.singleFile } - val dackkaOutputDirectory = File(project.buildDir, "dackkaDocumentation") dackkaJarFile.set(dackkaFile) - outputDirectory.set(dackkaOutputDirectory) + clientName.set(project.firebaseConfigValue { artifactId }) } - // TODO(b/243833009): Make task cacheable - private fun registerFiresiteTransformTask(project: Project, outputDirectory: Provider) = - project.tasks.register("firesiteTransform") { - mustRunAfter("generateDackkaDocumentation") + // TODO(b/248302613): Remove when dackka exposes configuration for this + private fun registerSeparateJavadocAndKotlinDoc( + project: Project, + dackkaOutputDirectory: Provider, + outputDirectory: Provider + ): TaskProvider { + val outputJavadocFolder = project.childFile(outputDirectory, "android") + val outputKotlindocFolder = project.childFile(outputDirectory, "kotlin") + + val separateJavadoc = project.tasks.register("separateJavadoc") { + dependsOn("generateDackkaDocumentation") + + val javadocClientFolder = project.childFile(dackkaOutputDirectory, "reference/client") + val javadocComFolder = project.childFile(dackkaOutputDirectory, "reference/com") + + fromDirectory(javadocClientFolder) + fromDirectory(javadocComFolder) - dackkaFiles.set(outputDirectory) + into(outputJavadocFolder) } + val separateKotlindoc = project.tasks.register("separateKotlindoc") { + dependsOn("generateDackkaDocumentation") + + val kotlindocFolder = project.childFile(dackkaOutputDirectory, "reference/kotlin") + + from(kotlindocFolder) + + into(outputKotlindocFolder) + } + + return project.tasks.register("separateJavadocAndKotlinDoc") { + dependsOn(separateJavadoc, separateKotlindoc) + } + } + + private fun registerFiresiteTransformTask( + project: Project, + separatedFilesDirectory: Provider, + targetDirectory: Provider + ): TaskProvider { + val transformJavadoc = project.tasks.register("firesiteTransformJavadoc") { + dependsOnAndMustRunAfter("separateJavadoc") + + referenceHeadTagsPath.set("docs/reference/android") + dackkaFiles.set(project.childFile(separatedFilesDirectory, "android")) + outputDirectory.set(project.childFile(targetDirectory, "android")) + } + + val transformKotlindoc = project.tasks.register("firesiteTransformKotlindoc") { + dependsOnAndMustRunAfter("separateKotlindoc") + + referenceHeadTagsPath.set("docs/reference/kotlin") + dackkaFiles.set(project.childFile(separatedFilesDirectory, "kotlin")) + outputDirectory.set(project.childFile(targetDirectory, "kotlin")) + } + + return project.tasks.register("firesiteTransform") { + dependsOn(transformJavadoc, transformKotlindoc) + } + } + // TODO(b/246593212): Migrate doc files to single directory private fun registerCopyJavaDocToCommonDirectoryTask(project: Project, outputDirectory: Provider) = project.tasks.register("copyJavaDocToCommonDirectory") { @@ -247,12 +323,10 @@ abstract class DackkaPlugin : Plugin { if (project.rootProject.findProperty("dackkaJavadoc") == "true") { mustRunAfter("firesiteTransform") - val outputFolder = project.file("${project.rootProject.buildDir}/firebase-kotlindoc/android") - val clientFolder = outputDirectory.map { project.file("${it.path}/reference/client") } - val comFolder = outputDirectory.map { project.file("${it.path}/reference/com") } + val outputFolder = project.rootProject.fileFromBuildDir("firebase-kotlindoc/android") + val javaFolder = project.childFile(outputDirectory, "android") - fromDirectory(clientFolder) - fromDirectory(comFolder) + fromDirectory(javaFolder) into(outputFolder) } @@ -263,8 +337,8 @@ abstract class DackkaPlugin : Plugin { project.tasks.register("copyKotlinDocToCommonDirectory") { mustRunAfter("firesiteTransform") - val outputFolder = project.file("${project.rootProject.buildDir}/firebase-kotlindoc") - val kotlinFolder = outputDirectory.map { project.file("${it.path}/reference/kotlin") } + val outputFolder = project.rootProject.fileFromBuildDir("firebase-kotlindoc") + val kotlinFolder = project.childFile(outputDirectory, "kotlin") fromDirectory(kotlinFolder) @@ -276,6 +350,9 @@ abstract class DackkaPlugin : Plugin { project.tasks.register("cleanDackkaDocumentation") { group = "cleanup" - delete("${project.buildDir}/dackkaDocumentation") + val outputDirs = listOf("dackkaRawOutput", "dackkaSeparatedFiles", "dackkaTransformedFiles") + + delete(outputDirs.map { project.fileFromBuildDir(it) }) + delete(project.rootProject.fileFromBuildDir("firebase-kotlindoc")) } } diff --git a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FiresiteTransformTask.kt b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FiresiteTransformTask.kt index 1ddf097820c..c68279d5985 100644 --- a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FiresiteTransformTask.kt +++ b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FiresiteTransformTask.kt @@ -3,7 +3,12 @@ package com.google.firebase.gradle.plugins import java.io.File import org.gradle.api.DefaultTask import org.gradle.api.provider.Property +import org.gradle.api.tasks.CacheableTask +import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskAction /** @@ -17,14 +22,23 @@ import org.gradle.api.tasks.TaskAction * - Appends /docs/ to hyperlinks in html files * - Removes the prefix path from book_path * - Removes the firebase prefix from all links + * - Changes the path for _reference-head-tags at the top of html files * * **Please note:** * This task is idempotent- meaning it can safely be ran multiple times on the same set of files. */ +@CacheableTask abstract class FiresiteTransformTask : DefaultTask() { @get:InputDirectory + @get:PathSensitive(PathSensitivity.RELATIVE) abstract val dackkaFiles: Property + @get:Input + abstract val referenceHeadTagsPath: Property + + @get:OutputDirectory + abstract val outputDirectory: Property + @TaskAction fun build() { val namesOfFilesWeDoNotNeed = listOf( @@ -33,21 +47,25 @@ abstract class FiresiteTransformTask : DefaultTask() { "packages.html", "package-list" ) + val rootDirectory = dackkaFiles.get() + val targetDirectory = outputDirectory.get() + targetDirectory.deleteRecursively() + + rootDirectory.walkTopDown().forEach { + if (it.name !in namesOfFilesWeDoNotNeed) { + val relativePath = it.toRelativeString(rootDirectory) + val newFile = it.copyTo(File("${targetDirectory.path}/$relativePath"), true) - dackkaFiles.get().walkTopDown().forEach { - if (it.name in namesOfFilesWeDoNotNeed) { - it.delete() - } else { when (it.extension) { - "html" -> it.fixHTMLFile() - "yaml" -> it.fixYamlFile() + "html" -> newFile.fixHTMLFile() + "yaml" -> newFile.fixYamlFile() } } } } private fun File.fixHTMLFile() { - val fixedContent = readText().fixBookPath().fixHyperlinks().removeLeadingFirebaseDomainInLinks() + val fixedContent = readText().fixBookPath().fixHyperlinks().removeLeadingFirebaseDomainInLinks().fixReferenceHeadTagsPath() writeText(fixedContent) } @@ -56,28 +74,33 @@ abstract class FiresiteTransformTask : DefaultTask() { writeText(fixedContent) } + // We utilize difference reference head tags between Kotlin and Java docs + // TODO(b/248316730): Remove when dackka exposes configuration for this + private fun String.fixReferenceHeadTagsPath() = + replace(Regex("(?<=include \").*(?=/_reference-head-tags.html\" %})"), referenceHeadTagsPath.get()) + // We don't actually upload class or index files, // so these headers will throw not found errors if not removed. - // TODO(b/243674302): Remove when dackka supports this behavior + // TODO(b/243674302): Remove when dackka exposes configuration for this private fun String.removeClassHeader() = remove(Regex("- title: \"Class Index\"\n {2}path: \".+\"\n\n")) private fun String.removeIndexHeader() = remove(Regex("- title: \"Package Index\"\n {2}path: \".+\"\n\n")) // We use a common book for all sdks, wheres dackka expects each sdk to have its own book. - // TODO(b/243674303): Remove when dackka supports this behavior + // TODO(b/243674303): Remove when dackka exposes configuration for this private fun String.fixBookPath() = remove(Regex("(?<=setvar book_path ?%})(.+)(?=/_book.yaml\\{% ?endsetvar)")) // Our documentation lives under /docs/reference/ versus the expected /reference/ - // TODO(b/243674305): Remove when dackka supports this behavior + // TODO(b/243674305): Remove when dackka exposes configuration for this private fun String.fixHyperlinks() = replace(Regex("(?<=href=\")(/)(?=reference/.*\\.html)"), "/docs/") // The documentation will work fine without this. This is primarily to make sure that links // resolve to their local counter part. Meaning when the docs are staged, they will resolve to // staged docs instead of prod docs- and vise versa. - // TODO(b/243673063): Remove when dackka supports this behavior + // TODO(b/243673063): Remove when dackka exposes configuration for this private fun String.removeLeadingFirebaseDomainInLinks() = remove(Regex("(?<=\")(https://firebase\\.google\\.com)(?=/docs/reference)")) } diff --git a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/GradleUtils.kt b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/GradleUtils.kt index d3a5b18a98f..21abb2d98b4 100644 --- a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/GradleUtils.kt +++ b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/GradleUtils.kt @@ -1,6 +1,7 @@ package com.google.firebase.gradle.plugins import java.io.File +import org.gradle.api.Project import org.gradle.api.provider.Provider import org.gradle.api.tasks.Copy @@ -8,3 +9,27 @@ fun Copy.fromDirectory(directory: Provider) = from(directory) { into(directory.map { it.name }) } + +/** + * Creates a file at the buildDir for the given [Project]. + * + * Syntax sugar for: + * + * ``` + * project.file("${project.buildDir}/$path) + * ``` + */ +fun Project.fileFromBuildDir(path: String) = file("$buildDir/$path") + +/** + * Maps a file provider to another file provider as a sub directory. + * + * Syntax sugar for: + * + * ``` + * fileProvider.map { project.file("${it.path}/$path") } + * ``` + */ +fun Project.childFile(provider: Provider, childPath: String) = provider.map { + file("${it.path}/$childPath") +} diff --git a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/Metalava.kt b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/Metalava.kt index 830ed8eb0bb..6ea25710bbd 100644 --- a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/Metalava.kt +++ b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/Metalava.kt @@ -23,6 +23,7 @@ import org.gradle.api.artifacts.Configuration import org.gradle.api.file.FileCollection import org.gradle.api.provider.Property import org.gradle.api.provider.SetProperty +import org.gradle.api.tasks.Classpath import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.InputFiles @@ -68,7 +69,7 @@ abstract class GenerateStubsTask : DefaultTask() { @get:InputFiles abstract val sources: SetProperty - @get:InputFiles + @get:[InputFiles Classpath] lateinit var classPath: FileCollection @get:OutputDirectory diff --git a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/ProjectUtils.kt b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/ProjectUtils.kt index 1bd001f67f8..d79299fff1a 100644 --- a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/ProjectUtils.kt +++ b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/ProjectUtils.kt @@ -17,6 +17,7 @@ import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.artifacts.Configuration import org.gradle.api.attributes.Attribute +import org.gradle.api.provider.Provider fun Project.isAndroid(): Boolean = listOf("com.android.application", "com.android.library", "com.android.test") @@ -42,7 +43,7 @@ val Project.javadocConfig: Configuration val Project.dackkaConfig: Configuration get() = configurations.findByName("dackkaArtifacts") ?: configurations.create("dackkaArtifacts") { - dependencies.add(this@dackkaConfig.dependencies.create("com.google.devsite:dackka-fat:1.0.1")) + dependencies.add(this@dackkaConfig.dependencies.create("com.google.devsite:dackka-fat:1.0.3")) } /** @@ -50,8 +51,7 @@ val Project.dackkaConfig: Configuration */ fun Configuration.getJars() = incoming.artifactView { attributes { - // TODO(b/241795594): replace value with android-class instead of jar after agp upgrade - attribute(Attribute.of("artifactType", String::class.java), "jar") + attribute(Attribute.of("artifactType", String::class.java), "android-classes") } }.artifacts.artifactFiles @@ -63,6 +63,14 @@ fun T.dependsOnAndMustRunAfter(otherTask: R) { dependsOn(otherTask) } +/** + * Utility method to call [Task.mustRunAfter] and [Task.dependsOn] on the specified task + */ +fun T.dependsOnAndMustRunAfter(otherTask: Provider) { + mustRunAfter(otherTask) + dependsOn(otherTask) +} + /** * Utility method to call [Task.mustRunAfter] and [Task.dependsOn] on the specified task name */ diff --git a/buildSrc/src/test/kotlin/com/google/firebase/gradle/plugins/publishing.kt b/buildSrc/src/test/kotlin/com/google/firebase/gradle/plugins/publishing.kt index f71b21f4a38..92b69b844c5 100644 --- a/buildSrc/src/test/kotlin/com/google/firebase/gradle/plugins/publishing.kt +++ b/buildSrc/src/test/kotlin/com/google/firebase/gradle/plugins/publishing.kt @@ -29,6 +29,7 @@ data class Project( val externalDependencies: Set = setOf(), val releaseWith: Project? = null, val customizePom: String? = null, + val publishJavadoc: Boolean = false, val libraryType: LibraryType = LibraryType.ANDROID ) { fun generateBuildFile(): String { @@ -42,6 +43,7 @@ data class Project( firebaseLibrary { ${if (releaseWith != null) "releaseWith project(':${releaseWith.name}')" else ""} ${if (customizePom != null) "customizePom {$customizePom}" else ""} + ${"publishJavadoc = $publishJavadoc"} } ${if (libraryType == LibraryType.ANDROID) "android.compileSdkVersion = 26" else ""} diff --git a/ci/danger/Dangerfile b/ci/danger/Dangerfile index 23c578283cb..0efe1369e0b 100644 --- a/ci/danger/Dangerfile +++ b/ci/danger/Dangerfile @@ -71,28 +71,13 @@ def has_sdk_changes() } end -tester_team = [ - 'rlazo', - 'vkryachko', - 'yifanyang', - 'VinayGuthal', - 'davidmotson', - 'daymxn', - 'emilypgoogle' -] - -is_enabled = true if tester_team.include? github.pr_author - ### Actions # Warn if a changelog is left out on a non-trivial PR that has modified # SDK source files. # -# TODO: remove the `is_enabled` after tests are complete -if is_enabled && has_sdk_changes() - if !has_changelog_changes && !declared_trivial - warning = "Did you forget to add a changelog entry? (Add the 'no-changelog'"\ - " label to the PR to silence this warning.)" - warn(warning) - end +if has_sdk_changes() && !has_changelog_changes && !declared_trivial + warning = "Did you forget to add a changelog entry? (Add the 'no-changelog'"\ + " label to the PR to silence this warning.)" + warn(warning) end diff --git a/ci/fireci/fireciplugins/fireperf.py b/ci/fireci/fireciplugins/fireperf.py index 8e336e5390f..b696ee963f1 100644 --- a/ci/fireci/fireciplugins/fireperf.py +++ b/ci/fireci/fireciplugins/fireperf.py @@ -52,7 +52,8 @@ def fireperf_e2e_test(target_environment, plugin_repo_dir): '--build-cache', '--parallel', '--continue', - ':firebase-perf:e2e-app:deviceCheck' + ':firebase-perf:e2e-app:deviceCheck', + gradle.P('instrumentFireperfE2ETest', 'true') ] if target_environment == 'autopush': fireperf_e2e_test_gradle_command += [gradle.P('fireperfBuildForAutopush', 'true')] diff --git a/ci/fireci/fireciplugins/macrobenchmark.py b/ci/fireci/fireciplugins/macrobenchmark.py index 0494c2f65b0..a0fc2f81a39 100644 --- a/ci/fireci/fireciplugins/macrobenchmark.py +++ b/ci/fireci/fireciplugins/macrobenchmark.py @@ -21,6 +21,7 @@ import re import shutil import sys +import tempfile import uuid import click @@ -31,42 +32,55 @@ from fireci import ci_command from fireci import ci_utils -from fireci.dir_utils import chdir from fireci import uploader +from fireci.dir_utils import chdir _logger = logging.getLogger('fireci.macrobenchmark') +@click.option( + '--build-only/--no-build-only', + default=False, + help='Whether to only build tracing test apps or to also run them on FTL afterwards' +) @ci_command() -def macrobenchmark(): +def macrobenchmark(build_only): """Measures app startup times for Firebase SDKs.""" - asyncio.run(_launch_macrobenchmark_test()) + asyncio.run(_launch_macrobenchmark_test(build_only)) -async def _launch_macrobenchmark_test(): +async def _launch_macrobenchmark_test(build_only): _logger.info('Starting macrobenchmark test...') - artifact_versions, config, _, _ = await asyncio.gather( - _parse_artifact_versions(), - _parse_config_yaml(), - _create_gradle_wrapper(), - _copy_google_services(), - ) - + artifact_versions = await _assemble_all_artifacts() _logger.info(f'Artifact versions: {artifact_versions}') - with chdir('health-metrics/macrobenchmark'): - runners = [MacrobenchmarkTest(k, v, artifact_versions) for k, v in config.items()] - results = await asyncio.gather(*[x.run() for x in runners], return_exceptions=True) + test_dir = await _prepare_test_directory() + _logger.info(f'Directory for test apps: {test_dir}') + + config = await _process_config_yaml() + _logger.info(f'Processed yaml configurations: {config}') + + tests = [MacrobenchmarkTest(app, artifact_versions, os.getcwd(), test_dir) for app in config['test-apps']] - await _post_processing(results) + _logger.info(f'Building {len(tests)} macrobenchmark test apps...') + # TODO(yifany): investigate why it is much slower with asyncio.gather + # - on corp workstations (9 min) than M1 macbook pro (3 min) + # - with gradle 7.5.1 (9 min) than gradle 6.9.2 (5 min) + # await asyncio.gather(*[x.build() for x in tests]) + for test in tests: + await test.build() + + if not build_only: + _logger.info(f'Submitting {len(tests)} tests to Firebase Test Lab...') + results = await asyncio.gather(*[x.test() for x in tests], return_exceptions=True) + await _post_processing(results) _logger.info('Macrobenchmark test finished.') -async def _parse_artifact_versions(): - proc = await asyncio.subprocess.create_subprocess_exec('./gradlew', 'assembleAllForSmokeTests') - await proc.wait() +async def _assemble_all_artifacts(): + await (await asyncio.create_subprocess_exec('./gradlew', 'assembleAllForSmokeTests')).wait() with open('build/m2repository/changed-artifacts.json') as json_file: artifacts = json.load(json_file) @@ -78,35 +92,36 @@ def _artifact_key_version(artifact): return f'{group_id}:{artifact_id}', version -async def _parse_config_yaml(): - with open('health-metrics/macrobenchmark/config.yaml') as yaml_file: - return yaml.safe_load(yaml_file) +async def _process_config_yaml(): + with open('health-metrics/benchmark/config.yaml') as yaml_file: + config = yaml.safe_load(yaml_file) + for app in config['test-apps']: + app['plugins'] = app.get('plugins', []) + app['traces'] = app.get('traces', []) + app['plugins'].extend(config['common-plugins']) + app['traces'].extend(config['common-traces']) + return config -async def _create_gradle_wrapper(): - with open('health-metrics/macrobenchmark/settings.gradle', 'w'): - pass +async def _prepare_test_directory(): + test_dir = tempfile.mkdtemp(prefix='benchmark-test-') - proc = await asyncio.subprocess.create_subprocess_exec( - './gradlew', - 'wrapper', - '--gradle-version', - '6.9', - '--project-dir', - 'health-metrics/macrobenchmark' - ) - await proc.wait() + # Required for creating gradle wrapper, as the dir is not defined in the root settings.gradle + open(os.path.join(test_dir, 'settings.gradle'), 'w').close() + command = ['./gradlew', 'wrapper', '--gradle-version', '7.5.1', '--project-dir', test_dir] + await (await asyncio.create_subprocess_exec(*command)).wait() -async def _copy_google_services(): - if 'FIREBASE_CI' in os.environ: - src = os.environ['FIREBASE_GOOGLE_SERVICES_PATH'] - dst = 'health-metrics/macrobenchmark/template/app/google-services.json' - _logger.info(f'Running on CI. Copying "{src}" to "{dst}"...') - shutil.copyfile(src, dst) + return test_dir async def _post_processing(results): + _logger.info(f'Macrobenchmark results: {results}') + + if os.getenv('CI') is None: + _logger.info('Running locally. Results upload skipped.') + return + # Upload successful measurements to the metric service measurements = [] for result in results: @@ -130,24 +145,29 @@ class MacrobenchmarkTest: """Builds the test based on configurations and runs the test on FTL.""" def __init__( self, - sdk_name, test_app_config, artifact_versions, + repo_root_dir, + test_dir, logger=_logger ): - self.sdk_name = sdk_name self.test_app_config = test_app_config self.artifact_versions = artifact_versions - self.logger = MacrobenchmarkLoggerAdapter(logger, sdk_name) - self.test_app_dir = os.path.join('test-apps', test_app_config['name']) + self.repo_root_dir = repo_root_dir + self.test_dir = test_dir + self.logger = MacrobenchmarkLoggerAdapter(logger, test_app_config['sdk']) + self.test_app_dir = os.path.join(test_dir, test_app_config['name']) self.test_results_bucket = 'fireescape-benchmark-results' self.test_results_dir = str(uuid.uuid4()) self.gcs_client = storage.Client() - async def run(self): - """Starts the workflow of src creation, apks assembly, FTL testing and results upload.""" + async def build(self): + """Creates test app project and assembles app and test apks.""" await self._create_benchmark_projects() await self._assemble_benchmark_apks() + + async def test(self): + """Runs benchmark tests on FTL and fetches FTL results from GCS.""" await self._execute_benchmark_tests() return await self._aggregate_benchmark_results() @@ -155,26 +175,33 @@ async def _create_benchmark_projects(self): app_name = self.test_app_config['name'] self.logger.info(f'Creating test app "{app_name}"...') - mustache_context = await self._prepare_mustache_context() + self.logger.info(f'Copying project template files into "{self.test_app_dir}"...') + template_dir = os.path.join(self.repo_root_dir, 'health-metrics/benchmark/template') + shutil.copytree(template_dir, self.test_app_dir) + + self.logger.info(f'Copying gradle wrapper binary into "{self.test_app_dir}"...') + shutil.copy(os.path.join(self.test_dir, 'gradlew'), self.test_app_dir) + shutil.copy(os.path.join(self.test_dir, 'gradlew.bat'), self.test_app_dir) + shutil.copytree(os.path.join(self.test_dir, 'gradle'), os.path.join(self.test_app_dir, 'gradle')) - shutil.copytree('template', self.test_app_dir) with chdir(self.test_app_dir): + mustache_context = await self._prepare_mustache_context() renderer = pystache.Renderer() mustaches = glob.glob('**/*.mustache', recursive=True) for mustache in mustaches: + self.logger.info(f'Processing template file: {mustache}') result = renderer.render_path(mustache, mustache_context) - original_name = mustache[:-9] # TODO(yifany): mustache.removesuffix('.mustache') + original_name = mustache.removesuffix('.mustache') with open(original_name, 'w') as file: file.write(result) async def _assemble_benchmark_apks(self): - executable = './gradlew' - args = ['assemble', 'assembleAndroidTest', '--project-dir', self.test_app_dir] - await self._exec_subprocess(executable, args) + with chdir(self.test_app_dir): + await self._exec_subprocess('./gradlew', ['assemble']) async def _execute_benchmark_tests(self): - app_apk_path = glob.glob(f'{self.test_app_dir}/app/**/*.apk', recursive=True)[0] - test_apk_path = glob.glob(f'{self.test_app_dir}/benchmark/**/*.apk', recursive=True)[0] + app_apk_path = glob.glob(f'{self.test_app_dir}/**/app-benchmark.apk', recursive=True)[0] + test_apk_path = glob.glob(f'{self.test_app_dir}/**/macrobenchmark-benchmark.apk', recursive=True)[0] self.logger.info(f'App apk: {app_apk_path}') self.logger.info(f'Test apk: {test_apk_path}') @@ -189,7 +216,7 @@ async def _execute_benchmark_tests(self): args += ['--type', 'instrumentation'] args += ['--app', app_apk_path] args += ['--test', test_apk_path] - args += ['--device', 'model=redfin,version=30,locale=en,orientation=portrait'] + args += ['--device', 'model=oriole,version=32,locale=en,orientation=portrait'] args += ['--directories-to-pull', '/sdcard/Download'] args += ['--results-bucket', f'gs://{self.test_results_bucket}'] args += ['--results-dir', self.test_results_dir] @@ -200,19 +227,13 @@ async def _execute_benchmark_tests(self): await self._exec_subprocess(executable, args) async def _prepare_mustache_context(self): - app_name = self.test_app_config['name'] - mustache_context = { - 'plugins': [], + 'm2repository': os.path.join(self.repo_root_dir, 'build/m2repository'), + 'plugins': self.test_app_config.get('plugins', []), + 'traces': self.test_app_config.get('traces', []), 'dependencies': [], } - if app_name != 'baseline': - mustache_context['plugins'].append('com.google.gms.google-services') - - if 'plugins' in self.test_app_config: - mustache_context['plugins'].extend(self.test_app_config['plugins']) - if 'dependencies' in self.test_app_config: for dep in self.test_app_config['dependencies']: if '@' in dep: @@ -234,9 +255,9 @@ async def _aggregate_benchmark_results(self): for benchmark in benchmarks: method = benchmark['name'] clazz = benchmark['className'].split('.')[-1] - runs = benchmark['metrics']['startupMs']['runs'] + runs = benchmark['metrics']['timeToInitialDisplayMs']['runs'] results.append({ - 'sdk': self.sdk_name, + 'sdk': self.test_app_config['sdk'], 'device': device, 'name': f'{clazz}.{method}', 'min': min(runs), diff --git a/firebase-abt/CHANGELOG.md b/firebase-abt/CHANGELOG.md new file mode 100644 index 00000000000..931ae65ff4d --- /dev/null +++ b/firebase-abt/CHANGELOG.md @@ -0,0 +1,38 @@ +# Unreleased + +# 21.1.0 +* [changed] Internal changes to ensure functionality alignment with other + SDK releases. + +# 21.0.2 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + +# 21.0.1 +* [changed] Updated dependencies of `play-services-basement`, + `play-services-base`, and `play-services-tasks` to their latest versions + (v18.0.0, v18.0.1, and v18.0.1, respectively). For more information, see the + [note](#basement18-0-0_base18-0-1_tasks18-0-1) at the top of this release + entry. + +# 21.0.0 +* [changed] Internal infrastructure improvements. +* [changed] Internal changes to support dynamic feature modules. + +# 20.0.0 +* [removed] Removed the protocol buffer dependency and moved relevant protocol + buffer definitions to [inappmessaging_longer]. If you use [ab_testing] + with [inappmessaging], you'll need to update to + [inappmessaging] v19.1.2 or later. + +# 19.0.1 +- [changed] Internal changes to ensure functionality alignment with other SDK releases. + +# 17.1.1 +* [changed] Updated API to support the latest [remote_config] update. + +* [changed] Updated minSdkVersion to API level 16. + +# 17.1.0 +* [changed] Updated API to support the latest [remote_config] update. + diff --git a/firebase-abt/firebase-abt.gradle b/firebase-abt/firebase-abt.gradle index 54945fe3f55..914f93550a8 100644 --- a/firebase-abt/firebase-abt.gradle +++ b/firebase-abt/firebase-abt.gradle @@ -19,6 +19,7 @@ plugins { firebaseLibrary { testLab.enabled = false publishSources = true + publishJavadoc = false } android { diff --git a/firebase-abt/src/main/java/com/google/firebase/abt/component/AbtRegistrar.java b/firebase-abt/src/main/java/com/google/firebase/abt/component/AbtRegistrar.java index 862b42b5770..137adab8633 100644 --- a/firebase-abt/src/main/java/com/google/firebase/abt/component/AbtRegistrar.java +++ b/firebase-abt/src/main/java/com/google/firebase/abt/component/AbtRegistrar.java @@ -32,11 +32,13 @@ */ @Keep public class AbtRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-abt"; @Override public List> getComponents() { return Arrays.asList( Component.builder(AbtComponent.class) + .name(LIBRARY_NAME) .add(Dependency.required(Context.class)) .add(Dependency.optionalProvider(AnalyticsConnector.class)) .factory( @@ -45,6 +47,6 @@ public List> getComponents() { container.get(Context.class), container.getProvider(AnalyticsConnector.class))) .build(), - LibraryVersionComponent.create("fire-abt", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/firebase-appdistribution-api/CHANGELOG.md b/firebase-appdistribution-api/CHANGELOG.md index 79e701b844d..26e49b1c933 100644 --- a/firebase-appdistribution-api/CHANGELOG.md +++ b/firebase-appdistribution-api/CHANGELOG.md @@ -1 +1,56 @@ # Unreleased + +# 16.0.0-beta05 +* [unchanged] Updated to accommodate the release of the updated + [appdistro] Kotlin extensions library. + + +## Kotlin +The Kotlin extensions library transitively includes the updated + `firebase-appdistribution-api` library. The Kotlin extensions library has + the following additional updates: + +* [feature] Firebase now supports Kotlin coroutines. + With this release, we added + [`kotlinx-coroutines-play-services`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-play-services/){: .external} + to `firebase-appdistribution-api-ktx` as a transitive dependency, which + exposes the `Task.await()` suspend function to convert a + [`Task`](https://developers.google.com/android/guides/tasks) + into a Kotlin coroutine. + +# 16.0.0-beta04 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-appdistribution-api` library. The Kotlin extensions library has no +additional updates. + +# 16.0.0-beta03 +* [feature] The [appdistro] SDK has been split into two libraries: + + * `firebase-appdistribution-api` - The API-only library
+ This new API-only library is functional only when the full + [appdistro] SDK implementation (`firebase-appdistribution`) is present. + `firebase-appdistribution-api` can be included in all + [build variants](https://developer.android.com/studio/build/build-variants){: .external}. + + * `firebase-appdistribution` - The full SDK implementation
+ This full SDK implementation is optional and should only be included in + pre-release builds. + + Visit the documentation to learn how to + [add these SDKs](/docs/app-distribution/set-up-alerts?platform=android#add-appdistro) + to your Android app. + + +## Kotlin +With the removal of the Kotlin extensions library +`firebase-appdistribution-ktx`, its functionality has been moved to the new +API-only library: `firebase-appdistribution-api-ktx`. + +This new Kotlin extensions library transitively includes the +`firebase-appdistribution-api` library. The Kotlin extensions library has no +additional updates. diff --git a/firebase-appdistribution-api/src/main/java/com/google/firebase/appdistribution/FirebaseAppDistributionApiRegistrar.java b/firebase-appdistribution-api/src/main/java/com/google/firebase/appdistribution/FirebaseAppDistributionApiRegistrar.java index 27497c5a867..5cf9aeeb0c0 100644 --- a/firebase-appdistribution-api/src/main/java/com/google/firebase/appdistribution/FirebaseAppDistributionApiRegistrar.java +++ b/firebase-appdistribution-api/src/main/java/com/google/firebase/appdistribution/FirebaseAppDistributionApiRegistrar.java @@ -32,18 +32,20 @@ */ @Keep public class FirebaseAppDistributionApiRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-appdistribution-api"; @Override public @NonNull List> getComponents() { return Arrays.asList( Component.builder(FirebaseAppDistributionProxy.class) + .name(LIBRARY_NAME) .add(Dependency.optionalProvider(FirebaseAppDistribution.class)) .factory(this::buildFirebaseAppDistributionProxy) // construct FirebaseAppDistribution instance on startup so we can register for // activity lifecycle callbacks before the API is called .alwaysEager() .build(), - LibraryVersionComponent.create("fire-appdistribution-api", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } private FirebaseAppDistributionProxy buildFirebaseAppDistributionProxy( diff --git a/firebase-appdistribution/CHANGELOG.md b/firebase-appdistribution/CHANGELOG.md index 41217f8995c..de63b825eac 100644 --- a/firebase-appdistribution/CHANGELOG.md +++ b/firebase-appdistribution/CHANGELOG.md @@ -1,17 +1,57 @@ # Unreleased -# Released +# 16.0.0-beta05 +* [unchanged] Updated to accommodate the release of the updated + [appdistro] Kotlin extensions library. -## v20.0.6 (M112) +# 16.0.0-beta03 +* [feature] The [appdistro] SDK has been split into two libraries: -#### Android library -* {{feature}} The Firebase App Distribution Android SDK is now available in beta. You + * `firebase-appdistribution-api` - The API-only library
+ This new API-only library is functional only when the full + [appdistro] SDK implementation (`firebase-appdistribution`) is present. + `firebase-appdistribution-api` can be included in all + [build variants](https://developer.android.com/studio/build/build-variants){: .external}. + + * `firebase-appdistribution` - The full SDK implementation
+ This full SDK implementation is optional and should only be included in + pre-release builds. + + Visit the documentation to learn how to + [add these SDKs](/docs/app-distribution/set-up-alerts?platform=android#add-appdistro) + to your Android app. + + +## Kotlin +* [removed] The Kotlin extensions library `firebase-appdistribution-ktx` + has been removed. All its functionality has been moved to the new API-only + library: `firebase-appdistribution-api-ktx`. + +# 16.0.0-beta02 +* [fixed] Fixed a bug that prevented testers from signing in when the app had +an underscore in the package name. + +* [fixed] Fixed a UI bug where the APK download notification displayed the +incorrect error message. + +* [changed] Internal improvements to tests. + + +## Kotlin +The Kotlin extensions library transitively includes the base +`firebase-app-distribution` library. The Kotlin extensions library has no +additional updates. + +# 16.0.0-beta01 +* [feature] The [appdistro] Android SDK is now available in beta. You can use this SDK to notify testers in-app when a new test build is available. To learn more, visit the - [reference documentation](https://firebase.google.com/docs/reference/android/com/google/firebase/appdistribution/package-summary). + [[appdistro] reference documentation](/docs/reference/android/com/google/firebase/appdistribution/package-summary). + -#### Kotlin extensions -The Android library with Kotlin extensions is now available in +## Kotlin +The [appdistro] Android library with Kotlin extensions is now available in beta. The Kotlin extensions library transitively includes the base `firebase-app-distribution` library. To learn more, visit the -[KTX reference documentation](https://firebase.google.com/docs/reference/kotlin/com/google/firebase/appdistribution/ktx/package-summary). +[[appdistro] KTX reference documentation](/docs/reference/kotlin/com/google/firebase/appdistribution/ktx/package-summary). + diff --git a/firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/FirebaseAppDistributionRegistrar.java b/firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/FirebaseAppDistributionRegistrar.java index 56f7829416f..59b45a2e9f0 100644 --- a/firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/FirebaseAppDistributionRegistrar.java +++ b/firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/FirebaseAppDistributionRegistrar.java @@ -37,6 +37,7 @@ */ @Keep public class FirebaseAppDistributionRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-appdistribution"; private static String TAG = "Registrar:"; @@ -44,6 +45,7 @@ public class FirebaseAppDistributionRegistrar implements ComponentRegistrar { public @NonNull List> getComponents() { return Arrays.asList( Component.builder(FirebaseAppDistribution.class) + .name(LIBRARY_NAME) .add(Dependency.required(FirebaseApp.class)) .add(Dependency.requiredProvider(FirebaseInstallationsApi.class)) .factory(this::buildFirebaseAppDistribution) @@ -51,7 +53,7 @@ public class FirebaseAppDistributionRegistrar implements ComponentRegistrar { // activity lifecycle callbacks before the API is called .alwaysEager() .build(), - LibraryVersionComponent.create("fire-appdistribution", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } private FirebaseAppDistribution buildFirebaseAppDistribution(ComponentContainer container) { diff --git a/firebase-common/ktx/ktx.gradle b/firebase-common/ktx/ktx.gradle index fac922882f5..2d15573ab83 100644 --- a/firebase-common/ktx/ktx.gradle +++ b/firebase-common/ktx/ktx.gradle @@ -42,8 +42,13 @@ dependencies { implementation project(':firebase-components') implementation 'androidx.annotation:annotation:1.1.0' + // We're exposing this library as a transitive dependency so developers can + // get Kotlin Coroutines support out-of-the-box for methods that return a Task + api "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutinesVersion" + testImplementation "org.robolectric:robolectric:$robolectricVersion" testImplementation 'junit:junit:4.12' testImplementation "com.google.truth:truth:$googleTruthVersion" testImplementation 'androidx.test:core:1.2.0' + testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion" } diff --git a/firebase-common/ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt b/firebase-common/ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt index 62a2d757169..45bcaece248 100644 --- a/firebase-common/ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt +++ b/firebase-common/ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt @@ -15,10 +15,14 @@ package com.google.firebase.ktx import androidx.test.core.app.ApplicationProvider +import com.google.android.gms.tasks.Tasks import com.google.common.truth.Truth.assertThat import com.google.firebase.FirebaseApp import com.google.firebase.FirebaseOptions import com.google.firebase.platforminfo.UserAgentPublisher +import kotlinx.coroutines.tasks.await +import kotlinx.coroutines.test.runTest +import org.junit.Assert.fail import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @@ -36,6 +40,8 @@ fun withApp(name: String, block: FirebaseApp.() -> Unit) { } } +class TestException(message: String) : Exception(message) + @RunWith(RobolectricTestRunner::class) class VersionTests { @Test @@ -101,3 +107,33 @@ class KtxTests { } } } + +class CoroutinesPlayServicesTests { + // We are only interested in the await() function offered by kotlinx-coroutines-play-services + // So we're not testing the other functions provided by that library. + + @Test + fun `Task#await() resolves to the same result as Task#getResult()`() = runTest { + val task = Tasks.forResult(21) + + val expected = task.result + val actual = task.await() + + assertThat(actual).isEqualTo(expected) + assertThat(task.isSuccessful).isTrue() + assertThat(task.exception).isNull() + } + + @Test + fun `Task#await() throws an Exception for failing Tasks`() = runTest { + val task = Tasks.forException(TestException("some error happened")) + + try { + task.await() + fail("Task#await should throw an Exception") + } catch (e: Exception) { + assertThat(e).isInstanceOf(TestException::class.java) + assertThat(task.isSuccessful).isFalse() + } + } +} diff --git a/firebase-components/firebase-components.gradle b/firebase-components/firebase-components.gradle index f91e5a09567..9c48904de3b 100644 --- a/firebase-components/firebase-components.gradle +++ b/firebase-components/firebase-components.gradle @@ -18,6 +18,7 @@ plugins { firebaseLibrary { publishSources = true + publishJavadoc = false } android { diff --git a/firebase-components/firebase-dynamic-module-support/firebase-dynamic-module-support.gradle b/firebase-components/firebase-dynamic-module-support/firebase-dynamic-module-support.gradle index 1954341b7b0..78ecbfd7219 100644 --- a/firebase-components/firebase-dynamic-module-support/firebase-dynamic-module-support.gradle +++ b/firebase-components/firebase-dynamic-module-support/firebase-dynamic-module-support.gradle @@ -21,6 +21,7 @@ group = 'com.google.firebase' firebaseLibrary { testLab.enabled = false publishSources = true + publishJavadoc = false } android { diff --git a/firebase-components/firebase-dynamic-module-support/src/main/java/com/google/firebase/dynamicloading/DynamicLoadingRegistrar.java b/firebase-components/firebase-dynamic-module-support/src/main/java/com/google/firebase/dynamicloading/DynamicLoadingRegistrar.java index 2aad8b5ba7d..2eb941f7a93 100644 --- a/firebase-components/firebase-dynamic-module-support/src/main/java/com/google/firebase/dynamicloading/DynamicLoadingRegistrar.java +++ b/firebase-components/firebase-dynamic-module-support/src/main/java/com/google/firebase/dynamicloading/DynamicLoadingRegistrar.java @@ -23,11 +23,13 @@ import java.util.List; public class DynamicLoadingRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-dyn-mod"; @Override public List> getComponents() { return Arrays.asList( Component.builder(DynamicLoadingSupport.class) + .name(LIBRARY_NAME) .add(Dependency.required(Context.class)) .add(Dependency.required(ComponentLoader.class)) .alwaysEager() @@ -36,6 +38,6 @@ public List> getComponents() { new DynamicLoadingSupport( container.get(Context.class), container.get(ComponentLoader.class))) .build(), - LibraryVersionComponent.create("fire-dyn-mod", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/firebase-config/CHANGELOG.md b/firebase-config/CHANGELOG.md new file mode 100644 index 00000000000..55b6f7f666f --- /dev/null +++ b/firebase-config/CHANGELOG.md @@ -0,0 +1,370 @@ +# Unreleased + +# 21.2.0 +* [unchanged] Updated to accommodate the release of the updated + [remote_config] Kotlin extensions library. + + +## Kotlin +The Kotlin extensions library transitively includes the updated + `firebase-config` library. The Kotlin extensions library has the following + additional updates: + +* [feature] Firebase now supports Kotlin coroutines. + With this release, we added + [`kotlinx-coroutines-play-services`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-play-services/){: .external} + to `firebase-config-ktx` as a transitive dependency, which exposes the + `Task.await()` suspend function to convert a + [`Task`](https://developers.google.com/android/guides/tasks) into a Kotlin + coroutine. + +# 21.1.2 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 21.1.1 +* [fixed] Fixed a bug that caused HTTP errors in some locales. For more + information, see + GitHub Issue #3757 + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 21.1.0 + + +* [changed] Added first-open time to [remote_config] server requests. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 21.0.2 +* [changed] Updated dependencies of `play-services-basement`, + `play-services-base`, and `play-services-tasks` to their latest versions + (v18.0.0, v18.0.1, and v18.0.1, respectively). For more information, see the + [note](#basement18-0-0_base18-0-1_tasks18-0-1) at the top of this release + entry. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 21.0.1 +* [fixed] Fixed a bug in the initialization of [remote_config] with a + non-primary Firebase app. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 21.0.0 +* [changed] Internal infrastructure improvements. +* [changed] Internal changes to support dynamic feature modules. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 20.0.4 +* [changed] Improved condition targeting signals. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 20.0.3 +* [changed] Standardize support for other Firebase products that integrate + with [remote_config]. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 20.0.2 +* [fixed] Fixed an issue that was causing [remote_config] to return the + static default value even if a remote value was defined. (#2186) + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 20.0.1 +* [changed] Added support for other Firebase products to integrate with + [remote_config]. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 20.0.0 +* [removed] Removed the protocol buffer dependency. Also, removed support for + configs saved on device using the legacy protocol buffer format (the SDK + stopped using this legacy format starting with [remote_config] v16.3.0). + +* [removed] Removed the deprecated synchronous method + `FirebaseRemoteConfig.activateFetched()`. Use the asynchronous + [`FirebaseRemoteConfig.activate()`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#activate()) + instead. + +* [removed] Removed the deprecated synchronous methods + `FirebaseRemoteConfig.setDefaults(int)` and + `FirebaseRemoteConfig.setDefaults(Map)`. Use the asynchronous + [`FirebaseRemoteConfig.setDefaultsAsync(int)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#setDefaultsAsync(int)) + and [`FirebaseRemoteConfig.setDefaultsAsync(Map)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#setDefaultsAsync(Map)) + instead. + +* [removed] Removed the deprecated synchronous method + `FirebaseRemoteConfig.setConfigSettings(FirebaseRemoteConfigSettings)`. + Use the asynchronous + [`FirebaseRemoteConfig.setConfigSettingsAsync(FirebaseRemoteConfigSettings)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#setConfigSettingsAsync(FirebaseRemoteConfigSettings)) + instead. + +* [removed] Removed the deprecated method + `FirebaseRemoteConfig.getByteArray(String)`. Use + [`FirebaseRemoteConfig.getString(String)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#getString(String)) + instead. + +* [removed] Removed the deprecated methods + `FirebaseRemoteConfigSettings.isDeveloperModeEnabled()` and + `FirebaseRemoteConfigSettings.Builder.setDeveloperModeEnabled(boolean)`. Use + [`FirebaseRemoteConfigSettings#getMinimumFetchIntervalInSeconds()`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfigSettings#getMinimumFetchIntervalInSeconds()) + and [`FirebaseRemoteConfigSettings.Builder#setMinimumFetchIntervalInSeconds(long)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfigSettings.Builder#setMinimumFetchIntervalInSeconds(long)) + instead. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 19.2.0 +* [changed] Migrated to use the [firebase_installations] service _directly_ + instead of using an indirect dependency via the Firebase Instance ID SDK. + + {% include "docs/reference/android/client/_includes/_iid-indirect-dependency-solutions.html" %} + +* [changed] Updated the protocol buffer dependency to the newer + `protobuf-javalite` artifact. The new artifact is incompatible with the old + one, so this library needed to be upgraded to avoid conflicts. No developer + action is necessary. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 19.1.4 +* [changed] Updated dependency on the Firebase Instance ID library to v20.1.5, + which is a step towards a direct dependency on the Firebase installations + service in a future release. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 19.1.3 +* [fixed] Fixed an issue where [`FirebaseRemoteConfig.fetch()`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig.html#fetch()) +would sometimes report a misformatted language tag. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 19.1.2 +* [fixed] Resolved known issue where + [`FirebaseRemoteConfigSettings.Builder.setFetchTimeoutInSeconds()`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfigSettings.Builder) + was not always honored. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 19.1.1 +* [changed] Updated [`FirebaseRemoteConfig.fetch()`](docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig.html#fetch()) +implementation to use [`FirebaseInstanceId.getInstanceId()`](/docs/reference/android/com/google/firebase/iid/FirebaseInstanceId.html#getInstanceId()) +in favor of the deprecated [`FirebaseInstanceId.getToken()`](/docs/reference/android/com/google/firebase/iid/FirebaseInstanceId.html#getToken()). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 19.1.0 +* [changed] Added getters to the fields of the + [`FirebaseRemoteConfigSettings.Builder`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfigSettings.Builder) + object to provide better Kotlin patterns. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 19.0.4 +* [fixed] Resolved + [known issue](//github.com/firebase/firebase-android-sdk/issues/973) where + network calls may fail on devices using API 19 and earlier. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 19.0.3 +* [fixed] Resolved + [known issue](https://github.com/firebase/firebase-android-sdk/issues/787) + where the [firebase_remote_config] SDK threw an error when Android + [StrictMode](https://developer.android.com/reference/android/os/StrictMode) + was turned on. + +* [fixed] Resolved issue where setting Byte Arrays via + [`FirebaseRemoteConfig.setDefaultsAsync(int)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#setDefaultsAsync(int)), + [`FirebaseRemoteConfig.setDefaultsAsync(Map)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#setDefaultsAsync(Map)) + and their synchronous counterparts would cause `getByteArray` to return an + object reference instead of the Byte Array. Byte Arrays set via the + Firebase console were unaffected by this bug. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-config` library. The Kotlin extensions library has no additional +updates. + +# 19.0.2 +* [unchanged] Updated to accommodate the release of the [remote_config] + Kotlin extensions library. + + +## Kotlin +* [feature] The beta release of a [remote_config] Android library with + Kotlin extensions is now available. The Kotlin extensions library transitively + includes the base `firebase-config` library. To learn more, visit the + [[remote_config] KTX documentation](/docs/reference/kotlin/com/google/firebase/remoteconfig/ktx/package-summary). + +# 19.0.1 +* [fixed] Resolved known issue where certain unicode characters were not + encoded correctly. The issue was introduced in v19.0.0. + +# 19.0.0 +* [changed] Versioned to add nullability annotations to improve the Kotlin + developer experience. No other changes. + +# 17.0.0 +* [feature] Added an asynchronous way to set config settings: [`FirebaseRemoteConfig.setConfigSettingsAsync(FirebaseRemoteConfigSettings)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#setConfigSettingsAsync(FirebaseRemoteConfigSettings)). + +* [feature] Added [`FirebaseRemoteConfigServerException`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfigServerException) and [`FirebaseRemoteConfigClientException`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfigClientException) to provide more nuanced error reporting. + +* [changed] Updated all "cache expiration" references to "minimum fetch interval" and "cache" references to "local storage". + +* [deprecated] Deprecated developer mode. Use [`FirebaseRemoteConfigSettings.Builder.setMinimumFetchIntervalInSeconds(0L)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfigSettings.Builder#setMinimumFetchIntervalInSeconds(long)) instead. + +* [deprecated] Deprecated the synchronous [`FirebaseRemoteConfig.setConfigSettings(FirebaseRemoteConfigSettings)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#setConfigSettings(FirebaseRemoteConfigSettings)). Use the asynchronous [`FirebaseRemoteConfig.setConfigSettingsAsync(FirebaseRemoteConfigSettings)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#setConfigSettingsAsync(FirebaseRemoteConfigSettings)) instead. + +* [deprecated] Deprecated [`FirebaseRemoteConfigFetchException`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfigFetchException). Use the more granular [`FirebaseRemoteConfigServerException`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfigServerException) and [`FirebaseRemoteConfigClientException`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfigClientException) instead. + +* [removed] Removed all namespace methods. + +* [removed] Removed all default constructors for Exception classes. + +* [changed] Updated minSdkVersion to API level 16. + +# 16.5.0 +* [feature] Enabled multi-App support. Use [`FirebaseRemoteConfig.getInstance(FirebaseApp)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#getInstance(FirebaseApp)) to retrieve a singleton instance of [`FirebaseRemoteConfig`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig) for the given [`FirebaseApp`](/docs/reference/android/com/google/firebase/FirebaseApp). + +* [feature] Added a method that fetches configs and activates them: [`FirebaseRemoteConfig.fetchAndActivate()`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#fetchAndActivate()). + +* [feature] Network connection timeout for fetch requests is now customizable. To set the network timeout, use [`FirebaseRemoteConfigSettings.Builder.setFetchTimeoutInSeconds(long)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfigSettings.Builder#setFetchTimeoutInSeconds(long)). + +* [feature] The default minimum fetch interval is now customizable. To set the default minimum fetch interval, use [`FirebaseRemoteConfigSettings.Builder.setMinimumFetchIntervalInSeconds(long)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfigSettings.Builder#setMinimumFetchIntervalInSeconds(long)). + +* [feature] Added a way to get all activated configs as a Java `Map`: [`FirebaseRemoteConfig.getAll()`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#getAll()). + +* [feature] Added the ability to reset a Firebase Remote Config instance: [`FirebaseRemoteConfig.reset()`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#reset()). + +* [feature] Added a way to determine if the Firebase Remote Config instance has finished initializing. To get a task that will complete when the Firebase Remote Config instance is finished initializing, use [`FirebaseRemoteConfig.ensureInitialized()`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#ensureInitialized()). + +* [feature] Added an asynchronous way to activate configs: [`FirebaseRemoteConfig.activate()`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#activate()). + +* [feature] Added an asynchronous way to set defaults: [`FirebaseRemoteConfig.setDefaultsAsync(int)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#setDefaultsAsync(int)) and [`FirebaseRemoteConfig.setDefaultsAsync(Map)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#setDefaultsAsync(Map)). + +* [deprecated] Deprecated the synchronous [`FirebaseRemoteConfig.activateFetched()`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#activateFetched()). Use the asynchronous [`FirebaseRemoteConfig.activate()`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#activate()) instead. + +* [deprecated] Deprecated the synchronous [`FirebaseRemoteConfig.setDefaults(int)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#setDefaults(int)) and [`FirebaseRemoteConfig.setDefaults(Map)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#setDefalts(Map)). Use the asynchronous [`FirebaseRemoteConfig.setDefaultsAsync(int)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#setDefaultsAsync(int)) and [`FirebaseRemoteConfig.setDefaultsAsync(Map)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#setDefaultsAsync(Map)) instead. + +* [deprecated] Deprecated [`FirebaseRemoteConfig.getByteArray(String)`](/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#getByteArray(String)). + +* [deprecated] Deprecated all methods with a namespace parameter. + +# 16.4.1 +* [changed] The SDK now enforces Android API Key restrictions. +* [fixed] Resolved known issue where the local cache was not honored even if + it had not expired. The issue was introduced in version 16.3.0. + +# 16.4.0 +* [changed] Internal changes to ensure functionality alignment with other SDK releases. + +# 16.3.0 +* [changed] The [firebase_remote_config] SDK requires the + [firebase_remote_config] REST API. For Firebase projects created before + March 7, 2018, you must manually enable the REST API. For more information, + see our + [[remote_config] REST API user guide](https://firebase.google.com/docs/remote-config/use-config-rest#before_you_begin_enable_the_rest_api). + +* [changed] Refactored the implementation of [remote_config] to improve SDK + stability and speed, and to remove the Google Play Services dependency. + +* [changed] Improved error logs and exception messages. + +* [changed] Updated the Android documentation to reflect that + [remote_config] uses `Locale` to retrieve location information, similar to + iOS's use of `countryCode`. + +# 16.1.3 +* [fixed] Fixed an issue where [remote_config] experiments were not + collecting results. + +# 16.1.0 +* [fixed] Bug fixes and internal improvements to support Firebase Performance Monitoring features. + diff --git a/firebase-config/src/main/java/com/google/firebase/remoteconfig/RemoteConfigRegistrar.java b/firebase-config/src/main/java/com/google/firebase/remoteconfig/RemoteConfigRegistrar.java index 3051c4a9c27..d856c9d573d 100644 --- a/firebase-config/src/main/java/com/google/firebase/remoteconfig/RemoteConfigRegistrar.java +++ b/firebase-config/src/main/java/com/google/firebase/remoteconfig/RemoteConfigRegistrar.java @@ -37,10 +37,13 @@ */ @Keep public class RemoteConfigRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-rc"; + @Override public List> getComponents() { return Arrays.asList( Component.builder(RemoteConfigComponent.class) + .name(LIBRARY_NAME) .add(Dependency.required(Context.class)) .add(Dependency.required(FirebaseApp.class)) .add(Dependency.required(FirebaseInstallationsApi.class)) @@ -56,6 +59,6 @@ public List> getComponents() { container.getProvider(AnalyticsConnector.class))) .eagerInDefaultApp() .build(), - LibraryVersionComponent.create("fire-rc", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/firebase-config/src/main/java/com/google/firebase/remoteconfig/internal/ConfigFetchHttpClient.java b/firebase-config/src/main/java/com/google/firebase/remoteconfig/internal/ConfigFetchHttpClient.java index f16261ff700..dff74f24b02 100644 --- a/firebase-config/src/main/java/com/google/firebase/remoteconfig/internal/ConfigFetchHttpClient.java +++ b/firebase-config/src/main/java/com/google/firebase/remoteconfig/internal/ConfigFetchHttpClient.java @@ -413,7 +413,7 @@ private static ConfigContainer extractConfigs(JSONObject fetchResponse, Date fet // Do nothing if entries do not exist. } if (entries != null) { - containerBuilder.replaceConfigsWith(entries); + containerBuilder = containerBuilder.replaceConfigsWith(entries); } JSONArray experimentDescriptions = null; @@ -423,7 +423,7 @@ private static ConfigContainer extractConfigs(JSONObject fetchResponse, Date fet // Do nothing if entries do not exist. } if (experimentDescriptions != null) { - containerBuilder.withAbtExperiments(experimentDescriptions); + containerBuilder = containerBuilder.withAbtExperiments(experimentDescriptions); } JSONObject personalizationMetadata = null; @@ -433,7 +433,7 @@ private static ConfigContainer extractConfigs(JSONObject fetchResponse, Date fet // Do nothing if personalizationMetadata does not exist. } if (personalizationMetadata != null) { - containerBuilder.withPersonalizationMetadata(personalizationMetadata); + containerBuilder = containerBuilder.withPersonalizationMetadata(personalizationMetadata); } return containerBuilder.build(); diff --git a/firebase-config/src/test/java/com/google/firebase/remoteconfig/internal/ConfigFetchHandlerTest.java b/firebase-config/src/test/java/com/google/firebase/remoteconfig/internal/ConfigFetchHandlerTest.java index 320c616deb9..5dab49b6afa 100644 --- a/firebase-config/src/test/java/com/google/firebase/remoteconfig/internal/ConfigFetchHandlerTest.java +++ b/firebase-config/src/test/java/com/google/firebase/remoteconfig/internal/ConfigFetchHandlerTest.java @@ -1033,10 +1033,10 @@ private static ConfigContainer extractConfigs(JSONObject fetchResponse, Date fet ConfigContainer.newBuilder().withFetchTime(fetchTime); JSONObject entries = fetchResponse.getJSONObject(ENTRIES); - containerBuilder.replaceConfigsWith(entries); + containerBuilder = containerBuilder.replaceConfigsWith(entries); JSONArray experimentDescriptions = fetchResponse.getJSONArray(EXPERIMENT_DESCRIPTIONS); - containerBuilder.withAbtExperiments(experimentDescriptions); + containerBuilder = containerBuilder.withAbtExperiments(experimentDescriptions); return containerBuilder.build(); } diff --git a/firebase-crashlytics-ndk/CHANGELOG.md b/firebase-crashlytics-ndk/CHANGELOG.md index 99fdcf856fd..63ac39c0889 100644 --- a/firebase-crashlytics-ndk/CHANGELOG.md +++ b/firebase-crashlytics-ndk/CHANGELOG.md @@ -1,57 +1,171 @@ -# 17.1.0 +# Unreleased -- [changed] Updated `firebase-crashlytics` dependency to v17.1.0. +# 18.2.14 +* [changed] Updated `firebase-crashlytics` dependency to v18.2.14. -# 17.0.1 +# 18.2.13 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). -- [changed] Updated `firebase-crashlytics` dependency to v17.0.1. +# 18.2.12 +* [changed] Updated `firebase-crashlytics` dependency to v18.2.12. -# 17.0.0 +# 18.2.11 +* [changed] Updated `firebase-crashlytics` dependency to v18.2.11. + +# 18.2.10 +* [changed] Updated `firebase-crashlytics` dependency to v18.2.10. + +# 18.2.9 +* [changed] Updated `firebase-crashlytics` dependency to v18.2.9. + +# 18.2.8 +* [changed] Updated `firebase-crashlytics` dependency to v18.2.8. + +# 18.2.7 +* [changed] Updated `firebase-crashlytics` dependency to v18.2.7. + +# 18.2.6 +* [changed] Updated internal Crashpad version to commit `281ba7`. With this + change, disabling tagged pointers is no longer required, so the following can + be removed from your manifest's `application` tag: + `android:allowNativeHeapPointerTagging=false`. + +* [changed] Updated `firebase-crashlytics` dependency to v18.2.6. + +# 18.2.5 +* [changed] Internal improvements to [crashlytics] file management, to + ensure consistent creation and removal of intermediate [crashlytics] files. + +* [changed] Updated `firebase-crashlytics` dependency to v18.2.5. + +# 18.2.4 +* [changed] Added an obfuscation exclusion for + `com.google.firebase.crashlytics.ndk.FirebaseCrashlyticsNdk` to the Proguard + configuration for this AAR, to avoid potential reflection errors when + obfuscating NDK-enabled apps. + +* [changed] Updated `firebase-crashlytics` dependency to v18.2.4. + +# 18.2.3 +* [changed] Internal changes to support upcoming Unity crash reporting + improvements. + +* [changed] Updated `firebase-crashlytics` dependency to v18.2.3. + +# 18.2.1 +* [fixed] Improved support for NDK crash reporting when using + [Play Feature Delivery](/docs/android/learn-more#dynamic-feature-modules). + Previously, `firebase-crashlytics-ndk` needed to be a dependency of the app + module to consistently report native crashes for all supported Android + versions. [crashlytics] will now report native crashes when used as a + dependency of a feature module. + +* [changed] Updated `firebase-crashlytics` dependency to v18.2.1. + +# 18.2.0 +* [changed] Updated `firebase-crashlytics` dependency to v18.2.0. + +# 18.1.0 +* [changed] Updated `firebase-crashlytics` dependency to v18.1.0. + +# 18.0.1 +* [changed] Updated `firebase-crashlytics` dependency to v18.0.1, which fixes + a bug that could cause excessive disk usage from NDK crash report files when + crash reporting is disabled. -- [changed] The Firebase Crashlytics SDK for NDK is now generally +# 18.0.0 +* [changed] Internal changes to support dynamic feature modules. + +* [changed] Updated `firebase-crashlytics` dependency to v18.0.0. + +# 17.4.1 +* [changed] Updated `firebase-crashlytics` dependency to v17.4.1. + +# 17.4.0 +* [changed] Updated `firebase-crashlytics` dependency to v17.4.0. + +# 17.3.1 +* [changed] Updated `firebase-crashlytics` dependency to v17.3.1. + +# 17.3.0 +Note: To ensure proper symbolication of NDK crashes, you must use +[[crashlytics] Gradle plugin v2.4.0+](#crashlytics_gradle_plugin_v2-4-0) when +using this version of the [crashlytics] NDK SDK and above. + +* [fixed] Upgraded underlying native crash reporting library to + [Crashpad](//crashpad.chromium.org){: .external}. This addresses emerging issues + with capturing certain types of native crashes on Android 10+ using + [Breakpad](//chromium.googlesource.com/breakpad){: .external}. + ([Github Issue #1678](//github.com/firebase/firebase-android-sdk/issues/1678){: .external}) + +# 17.2.2 +* [changed] Updated `firebase-crashlytics` dependency to v17.2.2. + +# 17.2.1 +* [fixed] Fixed signal handler to properly release storage on app exit. + ([Github Issue #1749](https://github.com/firebase/firebase-android-sdk/issues/1749)) + +* [changed] Updated `firebase-crashlytics` dependency to v17.2.1. + +# 17.1.1 +* [changed] Updated `firebase-crashlytics` dependency to v17.1.1. + +# 17.1.0 +* [changed] Updated `firebase-crashlytics` dependency to v17.1.0. + +# 17.0.1 +* [changed] Updated `firebase-crashlytics` dependency to v17.0.1. + +# 17.0.0 +* [changed] The [firebase_crashlytics] SDK for NDK is now generally available. -- [changed] Updated `firebase-crashlytics` dependency to v17.0.0. +* [changed] Updated `firebase-crashlytics` dependency to v17.0.0. # 17.0.0-beta04 - -- [changed] Updated `firebase-crashlytics` dependency to v17.0.0-beta-04. +* [changed] Updated `firebase-crashlytics` dependency to v17.0.0-beta-04. # 17.0.0-beta03 +* [fixed] Updated package name in `AndroidManifest.xml` to reflect new + [firebase_crashlytics] NDK package name. -- [fixed] Updated package name in `AndroidManifest.xml` to reflect new - Firebase Crashlytics NDK package name. - -- [changed] Improved debug logging. +* [changed] Improved debug logging. -- [changed] Released new `crashlytics.h` with updated C++ APIs. +* [changed] Released new `crashlytics.h` with updated C++ APIs. -- [changed] Added ProGuard rules files to avoid obfuscating public APIs called +* [changed] Added ProGuard rules files to avoid obfuscating public APIs called from C++. # 17.0.0-beta01 - -This release includes the initial beta release of the Firebase Crashlytics +This release includes the initial beta release of the [firebase_crashlytics] SDK for NDK crash reporting. -The Firebase Crashlytics SDK for NDK is a new version of the Crashlytics +The [firebase_crashlytics] SDK for NDK is a new version of the [crashlytics] SDK for NDK crash reporting built _without_ Fabric and instead built entirely on Firebase. This new SDK has new and improved APIs as well as an artifact name change. The following release notes describe changes in the new SDK. - - If you're using Crashlytics for NDK crash reporting in your app for the - first time, follow the [getting started instructions](https://firebase.google.com/docs/crashlytics/get-started-new-sdk?platform=android). - - If you're upgrading from the legacy Fabric SDK to the - Firebase Crashlytics SDK for NDK crash reporting, follow the - [upgrade instructions](https://firebase.google.com/docs/crashlytics/upgrade-sdk?platform=android) - to update your app with the following SDK changes. - -Note: The following changes are only relevant to Crashlytics NDK users who -are upgrading from the legacy Fabric SDK. - - - [changed] Crashlytics NDK crash reporting will now start automatically - when the Crashlytics NDK dependency is included in your app. - - [changed] The Crashlytics Gradle plugin has new tasks to support - uploading symbol files to Crashlytics servers. See the - [Crashlytics Gradle plugin documentation](https://firebase.google.com/docs/crashlytics/ndk-reports-new-sdk) + + + - [changed] [crashlytics] NDK crash reporting will now start automatically + when the [crashlytics] NDK dependency is included in your app. + - [changed] The [crashlytics] Gradle plugin has new tasks to support + uploading symbol files to [crashlytics] servers. See the + [[crashlytics] Gradle plugin documentation](/docs/crashlytics/ndk-reports-new-sdk) for more information. + diff --git a/firebase-crashlytics-ndk/src/main/java/com/google/firebase/crashlytics/ndk/CrashlyticsNdkRegistrar.java b/firebase-crashlytics-ndk/src/main/java/com/google/firebase/crashlytics/ndk/CrashlyticsNdkRegistrar.java index 5d3f6eb5821..05a75f065f7 100644 --- a/firebase-crashlytics-ndk/src/main/java/com/google/firebase/crashlytics/ndk/CrashlyticsNdkRegistrar.java +++ b/firebase-crashlytics-ndk/src/main/java/com/google/firebase/crashlytics/ndk/CrashlyticsNdkRegistrar.java @@ -26,15 +26,18 @@ import java.util.List; public class CrashlyticsNdkRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-cls-ndk"; + @Override public List> getComponents() { return Arrays.asList( Component.builder(CrashlyticsNativeComponent.class) + .name(LIBRARY_NAME) .add(Dependency.required(Context.class)) .factory(this::buildCrashlyticsNdk) .eagerInDefaultApp() .build(), - LibraryVersionComponent.create("fire-cls-ndk", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } private CrashlyticsNativeComponent buildCrashlyticsNdk(ComponentContainer container) { diff --git a/firebase-crashlytics/CHANGELOG.md b/firebase-crashlytics/CHANGELOG.md index 9abf66f53e9..d356950122f 100644 --- a/firebase-crashlytics/CHANGELOG.md +++ b/firebase-crashlytics/CHANGELOG.md @@ -1,90 +1,401 @@ # Unreleased -- [added] Added a public API to allow bulk logging of custom keys and values. -# 17.1.0 +# 18.3.0 +* [changed] Improved crash reporting reliability for crashes that occur early + in the app's lifecycle. + + +## Kotlin +The Kotlin extensions library transitively includes the updated + `firebase-crashlytics` library. The Kotlin extensions library has the + following additional updates: + +* [feature] Firebase now supports Kotlin coroutines. + With this release, we added + [`kotlinx-coroutines-play-services`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-play-services/){: .external} + to `firebase-crashlytics-ktx` as a transitive dependency, which exposes the + `Task.await()` suspend function to convert a + [`Task`](https://developers.google.com/android/guides/tasks) into a Kotlin + coroutine. + +# 18.2.13 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 18.2.12 +* [changed] Internal changes to avoid accessing device-specific information. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 18.2.11 +* [changed] Improved crash reporting reliability for multi-process apps on + Android 28 and above. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 18.2.10 +* [fixed] Fixed a bug that could prevent unhandled exceptions from being + propogated to the default handler when the network is unavailable. + +* [changed] Internal changes to support on-demand fatal crash reporting for + Flutter apps. + +* [fixed] Fixed a bug that prevented [crashlytics] from initalizing on some + devices in some cases. (#3269) + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 18.2.9 +* [changed] Updated dependencies of `play-services-basement`, + `play-services-base`, and `play-services-tasks` to their latest versions + (v18.0.0, v18.0.1, and v18.0.1, respectively). For more information, see the + [note](#basement18-0-0_base18-0-1_tasks18-0-1) at the top of this release + entry. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 18.2.8 +* [changed] Updated to the latest version of the `firebase-datatransport` + library. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 18.2.7 +* [changed] Improved runtime efficiency of the + [`setCustomKey` functions](/docs/crashlytics/customize-crash-reports?platform=android#add-keys), + significantly reducing the number of `Task` objects and disk writes when keys + are updated frequently. + (#3254) +* [fixed] Fixed a StrictMode `DiskReadViolation`. + (#3265) + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 18.2.6 +* [changed] Internal changes to support future improvements to Flutter crash + reporting. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 18.2.5 +* [fixed] Fixed a bug that prevented some [crashlytics] session files from + being removed after the session ended. All session-specific files are now + properly cleaned up. +* [changed] Internal improvements to [crashlytics] file management, to + ensure consistent creation and removal of intermediate [crashlytics] files. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 18.2.4 +* [changed] Internal changes to support ANR collection and their upcoming + display in the console. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 18.2.3 +* [fixed] Fixed a race condition that prevented some launch-time crashes from + being reported to Crashlytics. + +* [changed] Internal changes to support upcoming Unity crash reporting + improvements. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 18.2.1 +* [fixed] Fixed a `ConcurrentModificationException` that could be logged to + logcat when setting multiple custom key/values in rapid succession. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 18.2.0 +* [changed] Internal changes. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 18.1.0 +* [changed] Internal changes to support upcoming Unity features. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. -- [fixed] Updated Crashlytics integration with Firebase Analytics to +# 18.0.1 +* [fixed] Fixed a bug that could prevent proper removal of [crashlytics] NDK + crash report files when crash reporting is disabled, resulting in excessive + disk use. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 18.0.0 +* [changed] Removed call to + [`FirebaseInstallations#getId()`](/docs/reference/android/com/google/firebase/installations/FirebaseInstallations#getId()) + when [automatic data collection](/docs/crashlytics/customize-crash-reports?platform=android#enable-reporting) + is disabled for [crashlytics]. [crashlytics] no longer makes any network + calls when reporting is disabled. + +* [changed] Internal changes to support dynamic feature modules. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 17.4.1 +* [changed] Improved rooted device detection. + (#2515) + +* [fixed] Fix an uncaught IllegalStateExeception that could be thrown if + [crashlytics] is unable to register a receiver that collects battery state + information. If registration fails due to the app already having registered + too many receivers, [crashlytics] will report default values for the battery + state rather than crashing. + (#2504) + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 17.4.0 +* [feature] Added the + [`setCustomKeys`](/docs/reference/android/com/google/firebase/crashlytics/CustomKeysAndValues) + API to allow bulk logging of custom keys and values. + ([Github PR #2443](//github.com/firebase/firebase-android-sdk/pull/2443){: .external}) + + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 17.3.1 +* [changed] Removed OkHttp dependency to eliminate conflicts with apps and + SDKs using incompatible versions. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 17.3.0 +* [changed] Clarified debug logs for crash reports enqueued to be sent via the + `firebase-datatransport` library. + +* [fixed] Addressed an issue which could cause a `RejectedExecutionException` + in rare cases. + ([Github Issue #2013](//github.com/firebase/firebase-android-sdk/issues/2013){: .external}) + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 17.2.2 +* [fixed] Fixed crash that can occur when using a built-in resource as the app + launcher icon. + ([Github Issue #1935](//github.com/firebase/firebase-android-sdk/issues/1935){: .external}) + +* [fixed] Fixed a bug preventing crash reports from being sent in some cases + when an app is using [crashlytics] on multiple processes. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 17.2.1 +* [fixed] Improved handling of asynchronous tasks that need to wait for + completion on the main thread. + ([Github PR #1739](//github.com/firebase/firebase-android-sdk/pull/1739){: .external}) + +* [changed] Added an overload to the `setCrashlyticsCollectionEnabled` API to + allow for passing `null` to clear any previously set value. + ([Github PR #1434](//github.com/firebase/firebase-android-sdk/pull/1434){: .external}) + +* [changed] Migrated to use the [firebase_installations] service _directly_ + instead of using an indirect dependency via the Firebase Instance ID SDK. + ([Github PR #1760](//github.com/firebase/firebase-android-sdk/pull/1760){: .external}) + + {% include "docs/reference/android/client/_includes/_iid-indirect-dependency-solutions.html" %} + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 17.1.1 +* [changed] To improve the reliability of submitting crash uploads on poor + networks, changed the Transport SDK to retry connection errors + ([Github Issue #1705](//github.com/firebase/firebase-android-sdk/issues/1705){: .external}) + and increased the number of retries before deleting events + ([Github Issue #1708](//github.com/firebase/firebase-android-sdk/issues/1708){: .external}). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-crashlytics` library. The Kotlin extensions library has no additional +updates. + +# 17.1.0 +* [fixed] Updated [crashlytics] integration with [firebase_analytics] to include native crashes in crash-free users counts. -- [fixed] Removed a harmless, yet unexpected `FileNotFoundException` log +* [fixed] Removed a harmless, yet unexpected `FileNotFoundException` log output that printed when an optional file is unavailable. - ([Github Issue #1559](//github.com/firebase/firebase-android-sdk/issues/1559#issuecomment-638387614)) + ([Github Issue #1559](//github.com/firebase/firebase-android-sdk/issues/1559#issuecomment-638387614){: .external}) -# 17.0.1 -- [fixed] Fixed an issue causing a `SQLiteException` when changing versions - of Crashlytics. - ([Github Issue #1531](https://github.com/firebase/firebase-android-sdk/issues/1531)) -- [fixed] Improved reliability of sending reports at crash time on Android API +## Kotlin +* [feature] The [firebase_crashlytics] Android library with Kotlin + extensions is now available. The Kotlin extensions library transitively + includes the base `firebase-crashlytics` library. To learn more, visit the + [[crashlytics] KTX documentation](/docs/reference/kotlin/com/google/firebase/crashlytics/ktx/package-summary). + +# 17.0.1 +* [fixed] Fixed an issue causing a `SQLiteException` when changing versions + of [crashlytics]. + ([Github Issue #1531](https://github.com/firebase/firebase-android-sdk/issues/1531){: .external}) + +* [fixed] Improved reliability of sending reports at crash time on Android API level 28+. # 17.0.0 +* [changed] The [firebase_crashlytics] SDK is now generally available. -- [changed] The Firebase Crashlytics SDK is now generally available. - -- [fixed] Fixed an issue that could cause apps to crash if a crash report +* [fixed] Fixed an issue that could cause apps to crash if a crash report payload is too large (rare). -- [changed] Updated dependency on the Firebase Instance ID library to v20.1.5, - which is a step towards a direct dependency on the Firebase Installations +* [changed] Updated dependency on the Firebase Instance ID library to v20.1.5, + which is a step towards a direct dependency on the [firebase_installations] service in a future release. # 17.0.0-beta04 +* [changed] Imposed a limit on the maximum crash report payload size. -- [changed] Imposed a limit on the maximum crash report payload size. - -- [fixed] Reduced crash report payload size. +* [fixed] Reduced crash report payload size. # 17.0.0-beta03 +* [fixed] Fixed internal bugs to improve crash analysis and grouping. -- [fixed] Fixed internal bugs to improve crash analysis and grouping. - -- [changed] Improved compatibility with Google Analytics. For best +* [changed] Improved compatibility with Google Analytics. For best performance, make sure you're using the latest versions of the - Firebase Crashlytics SDK and the Firebase SDK for Google Analytics. + [firebase_crashlytics] SDK and the Firebase SDK for Google Analytics. -- [changed] Updated remaining Crashlytics backend API calls to prepare +* [changed] Updated remaining [crashlytics] backend API calls to prepare for Fabric sunset. # 17.0.0-beta02 - -- [changed] Removed superfluous `D/FirebaseCrashlytics` prefix from logs. +* [changed] Removed superfluous `D/FirebaseCrashlytics` prefix from logs. ([#1202](https://github.com/firebase/firebase-android-sdk/issues/1202)) -- [changed] Updated Crashlytics backend API calls in preparation for +* [changed] Updated [crashlytics] backend API calls in preparation for Fabric sunset. -- [changed] Upgraded Firebase Analytics integration to improve crash-free +* [changed] Upgraded [firebase_analytics] integration to improve crash-free users accuracy. For improved performance, we recommend that you upgrade to the - latest version of the Firebase SDK for Firebase Analytics with this - version of Firebase Crashlytics. + latest version of the Firebase SDK for [firebase_analytics] with this + version of [firebase_crashlytics]. # 17.0.0-beta01 +This release for [firebase_crashlytics] includes the initial beta release of +the [firebase_crashlytics] SDK. -This release for Firebase Crashlytics includes the initial beta release of -the Firebase Crashlytics SDK. - -The Firebase Crashlytics SDK is a new version of the Crashlytics SDK +The [firebase_crashlytics] SDK is a new version of the [crashlytics] SDK built _without_ Fabric and instead built entirely on Firebase. This new SDK has new and improved APIs as well as an artifact name change. The following release notes describe changes in the new SDK. - - If you're using Crashlytics in your app for the first time, follow the - [getting started instructions](https://firebase.google.com/docs/crashlytics/get-started-new-sdk?platform=android). - - If you're upgrading from the legacy Fabric SDK to the - Firebase Crashlytics SDK, follow the [upgrade instructions](https://firebase.google.com/docs/crashlytics/upgrade-sdk?platform=android) - to update your app with the following SDK changes. - -Note: The following changes are only relevant to Crashlytics users who are -upgrading from the legacy Fabric SDK. + - [changed] Replaced static methods with new instance methods that are more consistent with other Firebase SDKs and more intuitive to use. The new APIs give your users more control over how you collect their data. - - [removed] Removed the Fabric Crashlytics API key. Now, Crashlytics + - [removed] Removed the Fabric [crashlytics] API key. Now, [crashlytics] will always use the `google-services.json` file to associate your app with your Firebase project. If you linked your app from Fabric, remove the Fabric API key from your `AndroidManifest.xml` file. - [removed] The `fabric.properties` and `crashlytics.properties` files are no longer supported. Remove them from your app. + diff --git a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/CrashlyticsRegistrar.java b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/CrashlyticsRegistrar.java index 49b2391f94e..b18d4f25750 100644 --- a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/CrashlyticsRegistrar.java +++ b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/CrashlyticsRegistrar.java @@ -29,10 +29,13 @@ /** @hide */ public class CrashlyticsRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-cls"; + @Override public List> getComponents() { return Arrays.asList( Component.builder(FirebaseCrashlytics.class) + .name(LIBRARY_NAME) .add(Dependency.required(FirebaseApp.class)) .add(Dependency.required(FirebaseInstallationsApi.class)) .add(Dependency.deferred(CrashlyticsNativeComponent.class)) @@ -40,7 +43,7 @@ public List> getComponents() { .factory(this::buildCrashlytics) .eagerInDefaultApp() .build(), - LibraryVersionComponent.create("fire-cls", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } private FirebaseCrashlytics buildCrashlytics(ComponentContainer container) { diff --git a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/Utils.java b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/Utils.java index e54542f9ad0..9c752158cdf 100644 --- a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/Utils.java +++ b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/Utils.java @@ -134,6 +134,29 @@ public static T awaitEvenIfOnMainThread(Task task) } } + /** Invokes latch.await(timeout, unit) uninterruptibly. */ + public static boolean awaitUninterruptibly(CountDownLatch latch, long timeout, TimeUnit unit) { + boolean interrupted = false; + try { + long remainingNanos = unit.toNanos(timeout); + long end = System.nanoTime() + remainingNanos; + + while (true) { + try { + // CountDownLatch treats negative timeouts just like zero. + return latch.await(remainingNanos, TimeUnit.NANOSECONDS); + } catch (InterruptedException e) { + interrupted = true; + remainingNanos = end - System.nanoTime(); + } + } + } finally { + if (interrupted) { + Thread.currentThread().interrupt(); + } + } + } + /** * ExecutorService that is used exclusively by the awaitEvenIfOnMainThread function. If the * Continuation which counts down the latch is called on the same thread which is waiting on the diff --git a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/send/ReportQueue.java b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/send/ReportQueue.java index 404cc77d9af..d25c86c0eff 100644 --- a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/send/ReportQueue.java +++ b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/send/ReportQueue.java @@ -14,17 +14,22 @@ package com.google.firebase.crashlytics.internal.send; +import android.annotation.SuppressLint; import com.google.android.datatransport.Event; +import com.google.android.datatransport.Priority; import com.google.android.datatransport.Transport; +import com.google.android.datatransport.runtime.ForcedSender; import com.google.android.gms.tasks.TaskCompletionSource; import com.google.firebase.crashlytics.internal.Logger; import com.google.firebase.crashlytics.internal.common.CrashlyticsReportWithSessionId; import com.google.firebase.crashlytics.internal.common.OnDemandCounter; +import com.google.firebase.crashlytics.internal.common.Utils; import com.google.firebase.crashlytics.internal.model.CrashlyticsReport; import com.google.firebase.crashlytics.internal.settings.Settings; import java.util.Locale; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -115,6 +120,18 @@ TaskCompletionSource enqueueReport( } } + @SuppressLint("DiscouragedApi") // best effort only + public void flushScheduledReportsIfAble() { + CountDownLatch latch = new CountDownLatch(1); + new Thread( + () -> { + ForcedSender.sendBlocking(transport, Priority.HIGHEST); + latch.countDown(); + }) + .start(); + Utils.awaitUninterruptibly(latch, 2, TimeUnit.SECONDS); + } + /** Send the report to Crashlytics through Google DataTransport. */ private void sendReport( CrashlyticsReportWithSessionId reportWithSessionId, @@ -128,6 +145,7 @@ private void sendReport( tcs.trySetException(error); return; } + flushScheduledReportsIfAble(); tcs.trySetResult(reportWithSessionId); }); } diff --git a/firebase-database-collection/firebase-database-collection.gradle b/firebase-database-collection/firebase-database-collection.gradle index 1764b056048..eb9e150cdae 100644 --- a/firebase-database-collection/firebase-database-collection.gradle +++ b/firebase-database-collection/firebase-database-collection.gradle @@ -18,6 +18,7 @@ plugins { firebaseLibrary { publishSources = true + publishJavadoc = false } android { diff --git a/firebase-database/CHANGELOG.md b/firebase-database/CHANGELOG.md index 81edabfb425..ebb5b3ed8f5 100644 --- a/firebase-database/CHANGELOG.md +++ b/firebase-database/CHANGELOG.md @@ -1,80 +1,240 @@ # Unreleased -- [fixed] Fixed a crash that prevented the RTDB SDK from reconnecting to the - backend if a token refresh attempt was unsuccesful. -- [fixed] `Query.get` no longer throws "Client is offline" exception when local + +# 20.1.0 +* [unchanged] Updated to accommodate the release of the updated +[database] Kotlin extensions library. + + +## Kotlin +The Kotlin extensions library transitively includes the updated + `firebase-database` library. The Kotlin extensions library has the following + additional updates: + +* [feature] Firebase now supports Kotlin coroutines. + With this release, we added + [`kotlinx-coroutines-play-services`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-play-services/){: .external} + to `firebase-database-ktx` as a transitive dependency, which exposes the + `Task.await()` suspend function to convert a + [`Task`](https://developers.google.com/android/guides/tasks) into a Kotlin + coroutine. + +* [feature] Added + [`Query.snapshots`](/docs/reference/kotlin/com/google/firebase/database/ktx/package-summary#snapshots) + and + [`Query.childEvents`](/docs/reference/kotlin/com/google/firebase/database/ktx/package-summary#childEvents) + Kotlin Flows to listen to realtime events. + +# 20.0.6 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + +* [fixed] Fixed issue where `Query.get()` was propagating events to + listeners on unrelated queries. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. + +# 20.0.5 +* [ fixed ] `Query.get` no longer throws "Client is offline" exception when local value is not available. Instead, it waits for a backend connection. + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. + +# 20.0.4 +* [changed] Updated dependencies of `play-services-basement`, + `play-services-base`, and `play-services-tasks` to their latest versions + (v18.0.0, v18.0.1, and v18.0.1, respectively). For more information, see the + [note](#basement18-0-0_base18-0-1_tasks18-0-1) at the top of this release + entry. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. + +# 20.0.3 +* [fixed] Fixed a crash that prevented the SDK from connecting to the +backend if a credential refresh was unsuccesful. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. + # 20.0.2 -- [fixed] The SDK can now continue to issue writes for apps that send an - invalid App Check tokens if AppCheck enforcement is not enabled. +* [fixed] The SDK can now continue to issue writes for apps that send + invalid [app_check] tokens if [app_check] enforcement is not enabled. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. # 20.0.1 -- [fixed] Fixed an issue where connections would hang when using appcheck - without Auth. +* [fixed] Fixed an issue that prevented clients from connecting to the + backend when the app used [app_check] without [auth]. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. + +# 20.0.0 +* [feature] Added abuse reduction features. + +* [changed] Internal changes to support dynamic feature modules. + +* [changed] Internal infrastructure improvements. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. # 19.7.0 -- [added] Added `Query.startAfter()` and `Query.endBefore()` filter for paginating - RTDB queries. -- [fixed] Fixed an issue with `Query.get()` that caused the client to go offline if - only `get()` operations were pending. +- [feature] Added [`Query#startAfter()`](/docs/reference/android/com/google/firebase/database/Query#startAfter(java.lang.String,%20java.lang.String)) + and [`Query#endBefore()`](/docs/reference/android/com/google/firebase/database/Query#endBefore(java.lang.String,%20java.lang.String)) + filters to help with paginated queries. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. # 19.6.0 -- [fixed] Fixed a crash on some Pixel devices that occurred when closing the +- [feature] Added [`DatabaseReference#get()`](/docs/reference/android/com/google/firebase/database/DatabaseReference#get()) + and [`Query#get()`](/docs/reference/android/com/google/firebase/database/Query#get()), + which return data from the server even when older data is available in the local + cache. +- [fixed] Fixed a crash that occured on some Pixel devices when closing the network connection. -- [added] Added `Query.get()`, which allows users to receive a single data - snapshot. `Query.get()` returns the latest value even if an older value - already exists in cache. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. # 19.5.1 -- [fixed] Fixes a regression in v19.4 that may cause assertion failures, - especially when persistence is enabled. +- [fixed] Fixed a regression introduced in v19.3.0 that may cause assertion + failures, especially when persistence is enabled. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. # 19.5.0 -- [changed] The SDK can now infer a default database URL if none is provided in - the config. +- [feature] The SDK can now infer a default database URL even if it is omitted +in the project's configuration. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. # 19.4.0 +- [feature] Added support for connecting to the Firebase Emulator Suite via + a new method, + [`FirebaseDatabase#useEmulator()`](/docs/reference/android/com/google/firebase/database/FirebaseDatabase#useEmulator(java.lang.String,%20int)). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. + +# 19.3.1 - [changed] Added internal HTTP header to the WebChannel connection. -- [feature] Realtime Database now supports connecting to a local emulator via - `FirebaseDatabase#useEmulator()` + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. # 19.3.0 -- [feature] Added ServerValue.increment() to support atomic field value increments - without transactions. +- [feature] Added [`ServerValue.increment()`](/docs/reference/android/com/google/firebase/database/ServerValue#increment(double)) + to support atomic field value increments without transactions. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. + +# 19.2.1 +- [changed] Internal changes to ensure functionality alignment with other SDK releases. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-database` library. The Kotlin extensions library has no additional +updates. # 19.2.0 -- [changed] Added support for type wildcards in GenericTypeIndicator, expanding - our custom class serialization to include classes with wildcard generics - (#792). +- [feature] Added support for type wildcards in + [`GenericTypeIndicator`](/docs/reference/android/com/google/firebase/database/GenericTypeIndicator), + expanding our custom class serialization to include classes with wildcard + generics. -# 19.1.1 -- [fixed] Fixed a crash that occurred when we attempted to start a network - connection during app shutdown (#672). + +## Kotlin +* [feature] The beta release of a [database] Android library with + Kotlin extensions is now available. The Kotlin extensions library transitively + includes the base `firebase-database` library. To learn more, visit the + [[database] KTX documentation](/docs/reference/kotlin/com/google/firebase/database/ktx/package-summary). # 19.1.0 -- [feature] Added support for the Firebase Database Emulator. To connect to - the emulator, specify "http:///?ns=" as your - Database URL (via `FirebaseDatabase.getInstance(String)`). - Note that if you are running the Database Emulator on "localhost" and - connecting from an app that is running inside an Android Emulator, the - emulator host will be "10.0.2.2" followed by its port. +- [feature] Added support for the [firebase_database] Emulator. To connect + to the emulator, specify "http://:/?ns=" as your + Database URL (via [`FirebaseDatabase.getInstance(String)`](/docs/reference/android/com/google/firebase/database/FirebaseDatabase.html#getSdkVersion())). + Note that if you are running the [database] Emulator on "localhost" and + connecting from an app that is running inside an Android Emulator, + the [database] Emulator host will be "10.0.2.2" followed by its port. + +# 19.0.0 +* [changed] Versioned to add nullability annotations to improve the Kotlin + developer experience. No other changes. # 18.0.1 -- [changed] The SDK now reports the correct version number (via - `FirebaseDatabase.getSdkVersion()`). +- [changed] Internal changes to ensure functionality alignment with other SDK + releases. +- [fixed] The SDK now reports the correct version number (via + [`FirebaseDatabase.getSdkVersion()`](/docs/reference/android/com/google/firebase/database/FirebaseDatabase.html#getSdkVersion()`). # 17.0.0 -- [changed] Added `@RestrictTo` annotations to discourage the use of APIs that - are not public. This affects internal APIs that were previously obfuscated - and are not mentioned in our documentation. -- [changed] Improved error messages for certain Number types that are not - supported by our serialization layer (#272). -- [internal] Updated the SDK initialization process and removed usages of - deprecated method. -- [changed] Added missing nullability annotations for better Kotlin interop. -- [internal] Removed `@PublicApi` annotations as they are no longer enforced - and have no semantic meaning. +* [changed] Internal changes that rely on an updated API to obtain + authentication credentials. If you use [firebase_auth], update to + `firebase-auth` v17.0.0 or later to ensure functionality alignment. # 16.0.6 -- [fixed] Fixed an issue that could cause a NullPointerException during the - initial handshake with the Firebase backend (#119). +* [fixed] Fixed a potential `NullPointerException` calling method + `java.lang.String.toLowerCase`. + (https://github.com/firebase/firebase-android-sdk/issues/179) + +# 16.0.3 +* [fixed] Fixed an initialization issue that prevented the Realtime Database +client from being initialized outside of Android's main thread. + +# 16.0.2 +* [fixed] This release includes minor fixes and improvements. + +# 16.0.1 +* [changed] Added `Nullability` annotations to all public API classes/methods. + diff --git a/firebase-database/ktx/api.txt b/firebase-database/ktx/api.txt index 4f3992e2c57..612fee97f23 100644 --- a/firebase-database/ktx/api.txt +++ b/firebase-database/ktx/api.txt @@ -1,11 +1,57 @@ // Signature format: 2.0 package com.google.firebase.database.ktx { + public abstract sealed class ChildEvent { + } + + public static final class ChildEvent.Added extends com.google.firebase.database.ktx.ChildEvent { + ctor public ChildEvent.Added(@NonNull com.google.firebase.database.DataSnapshot snapshot, @Nullable String previousChildName); + method @NonNull public com.google.firebase.database.DataSnapshot component1(); + method @Nullable public String component2(); + method @NonNull public com.google.firebase.database.ktx.ChildEvent.Added copy(@NonNull com.google.firebase.database.DataSnapshot snapshot, @Nullable String previousChildName); + method @Nullable public String getPreviousChildName(); + method @NonNull public com.google.firebase.database.DataSnapshot getSnapshot(); + property @Nullable public final String previousChildName; + property @NonNull public final com.google.firebase.database.DataSnapshot snapshot; + } + + public static final class ChildEvent.Changed extends com.google.firebase.database.ktx.ChildEvent { + ctor public ChildEvent.Changed(@NonNull com.google.firebase.database.DataSnapshot snapshot, @Nullable String previousChildName); + method @NonNull public com.google.firebase.database.DataSnapshot component1(); + method @Nullable public String component2(); + method @NonNull public com.google.firebase.database.ktx.ChildEvent.Changed copy(@NonNull com.google.firebase.database.DataSnapshot snapshot, @Nullable String previousChildName); + method @Nullable public String getPreviousChildName(); + method @NonNull public com.google.firebase.database.DataSnapshot getSnapshot(); + property @Nullable public final String previousChildName; + property @NonNull public final com.google.firebase.database.DataSnapshot snapshot; + } + + public static final class ChildEvent.Moved extends com.google.firebase.database.ktx.ChildEvent { + ctor public ChildEvent.Moved(@NonNull com.google.firebase.database.DataSnapshot snapshot, @Nullable String previousChildName); + method @NonNull public com.google.firebase.database.DataSnapshot component1(); + method @Nullable public String component2(); + method @NonNull public com.google.firebase.database.ktx.ChildEvent.Moved copy(@NonNull com.google.firebase.database.DataSnapshot snapshot, @Nullable String previousChildName); + method @Nullable public String getPreviousChildName(); + method @NonNull public com.google.firebase.database.DataSnapshot getSnapshot(); + property @Nullable public final String previousChildName; + property @NonNull public final com.google.firebase.database.DataSnapshot snapshot; + } + + public static final class ChildEvent.Removed extends com.google.firebase.database.ktx.ChildEvent { + ctor public ChildEvent.Removed(@NonNull com.google.firebase.database.DataSnapshot snapshot); + method @NonNull public com.google.firebase.database.DataSnapshot component1(); + method @NonNull public com.google.firebase.database.ktx.ChildEvent.Removed copy(@NonNull com.google.firebase.database.DataSnapshot snapshot); + method @NonNull public com.google.firebase.database.DataSnapshot getSnapshot(); + property @NonNull public final com.google.firebase.database.DataSnapshot snapshot; + } + public final class DatabaseKt { method @NonNull public static com.google.firebase.database.FirebaseDatabase database(@NonNull com.google.firebase.ktx.Firebase, @NonNull String url); method @NonNull public static com.google.firebase.database.FirebaseDatabase database(@NonNull com.google.firebase.ktx.Firebase, @NonNull com.google.firebase.FirebaseApp app); method @NonNull public static com.google.firebase.database.FirebaseDatabase database(@NonNull com.google.firebase.ktx.Firebase, @NonNull com.google.firebase.FirebaseApp app, @NonNull String url); + method @NonNull public static kotlinx.coroutines.flow.Flow getChildEvents(@NonNull com.google.firebase.database.Query); method @NonNull public static com.google.firebase.database.FirebaseDatabase getDatabase(@NonNull com.google.firebase.ktx.Firebase); + method @NonNull public static kotlinx.coroutines.flow.Flow getSnapshots(@NonNull com.google.firebase.database.Query); method public static inline T getValue(@NonNull com.google.firebase.database.DataSnapshot); method public static inline T getValue(@NonNull com.google.firebase.database.MutableData); } diff --git a/firebase-database/ktx/ktx.gradle b/firebase-database/ktx/ktx.gradle index c15a36557ef..7685a0b72af 100644 --- a/firebase-database/ktx/ktx.gradle +++ b/firebase-database/ktx/ktx.gradle @@ -17,6 +17,8 @@ plugins { id 'kotlin-android' } +group = "com.google.firebase" + firebaseLibrary { releaseWith project(':firebase-database') publishJavadoc = true @@ -50,6 +52,7 @@ dependencies { implementation project(':firebase-database') implementation 'androidx.annotation:annotation:1.1.0' implementation 'com.google.android.gms:play-services-tasks:18.0.1' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" androidTestImplementation 'junit:junit:4.12' androidTestImplementation "com.google.truth:truth:$googleTruthVersion" diff --git a/firebase-database/ktx/src/main/kotlin/com/google/firebase/database/ktx/ChildEvent.kt b/firebase-database/ktx/src/main/kotlin/com/google/firebase/database/ktx/ChildEvent.kt new file mode 100644 index 00000000000..aeadeec5f39 --- /dev/null +++ b/firebase-database/ktx/src/main/kotlin/com/google/firebase/database/ktx/ChildEvent.kt @@ -0,0 +1,43 @@ +package com.google.firebase.database.ktx + +import com.google.firebase.database.DataSnapshot + +/** + * Used to emit events about changes in the child locations of a given + * [Query] when using the [childEvents] Flow. + */ +sealed class ChildEvent { + /** + * Emitted when a new child is added to the location. + * + * @param snapshot An immutable snapshot of the data at the new child location + * @param previousChildName The key name of sibling location ordered before the new child. This + * will be null for the first child node of a location. + */ + data class Added(val snapshot: DataSnapshot, val previousChildName: String?) : ChildEvent() + + /** + * Emitted when the data at a child location has changed. + * + * @param snapshot An immutable snapshot of the data at the new data at the child location + * @param previousChildName The key name of sibling location ordered before the child. This will + * be null for the first child node of a location. + */ + data class Changed(val snapshot: DataSnapshot, val previousChildName: String?) : ChildEvent() + + /** + * Emitted when a child is removed from the location. + * + * @param snapshot An immutable snapshot of the data at the child that was removed. + */ + data class Removed(val snapshot: DataSnapshot) : ChildEvent() + + /** + * Emitted when a child location's priority changes. + * + * @param snapshot An immutable snapshot of the data at the location that moved. + * @param previousChildName The key name of the sibling location ordered before the child + * location. This will be null if this location is ordered first. + */ + data class Moved(val snapshot: DataSnapshot, val previousChildName: String?) : ChildEvent() +} diff --git a/firebase-database/ktx/src/main/kotlin/com/google/firebase/database/ktx/Database.kt b/firebase-database/ktx/src/main/kotlin/com/google/firebase/database/ktx/Database.kt index 4e607399cbe..b200948bf49 100644 --- a/firebase-database/ktx/src/main/kotlin/com/google/firebase/database/ktx/Database.kt +++ b/firebase-database/ktx/src/main/kotlin/com/google/firebase/database/ktx/Database.kt @@ -18,12 +18,20 @@ import androidx.annotation.Keep import com.google.firebase.FirebaseApp import com.google.firebase.components.Component import com.google.firebase.components.ComponentRegistrar +import com.google.firebase.database.ChildEventListener import com.google.firebase.database.DataSnapshot +import com.google.firebase.database.DatabaseError import com.google.firebase.database.FirebaseDatabase import com.google.firebase.database.GenericTypeIndicator import com.google.firebase.database.MutableData +import com.google.firebase.database.Query +import com.google.firebase.database.ValueEventListener import com.google.firebase.ktx.Firebase import com.google.firebase.platforminfo.LibraryVersionComponent +import kotlinx.coroutines.cancel +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.channels.trySendBlocking +import kotlinx.coroutines.flow.callbackFlow /** Returns the [FirebaseDatabase] instance of the default [FirebaseApp]. */ val Firebase.database: FirebaseDatabase @@ -59,6 +67,68 @@ inline fun MutableData.getValue(): T? { return getValue(object : GenericTypeIndicator() {}) } +/** + * Starts listening to this query and emits its values via a [Flow]. + * + * - When the returned flow starts being collected, a [ValueEventListener] will be attached. + * - When the flow completes, the listener will be removed. + */ +val Query.snapshots + get() = callbackFlow { + val listener = addValueEventListener(object : ValueEventListener { + override fun onDataChange(snapshot: DataSnapshot) { + repo.scheduleNow { + trySendBlocking(snapshot) + } + } + + override fun onCancelled(error: DatabaseError) { + cancel(message = "Error getting Query snapshot", cause = error.toException()) + } + }) + awaitClose { removeEventListener(listener) } + } + +/** + * Starts listening to this query's child events and emits its values via a [Flow]. + * + * - When the returned flow starts being collected, a [ChildEventListener] will be attached. + * - When the flow completes, the listener will be removed. + */ +val Query.childEvents + get() = callbackFlow { + val listener = addChildEventListener(object : ChildEventListener { + override fun onChildAdded(snapshot: DataSnapshot, previousChildName: String?) { + repo.scheduleNow { + trySendBlocking(ChildEvent.Added(snapshot, previousChildName)) + } + } + + override fun onChildChanged(snapshot: DataSnapshot, previousChildName: String?) { + repo.scheduleNow { + trySendBlocking(ChildEvent.Changed(snapshot, previousChildName)) + } + } + + override fun onChildRemoved(snapshot: DataSnapshot) { + repo.scheduleNow { + trySendBlocking(ChildEvent.Removed(snapshot)) + } + } + + override fun onChildMoved(snapshot: DataSnapshot, previousChildName: String?) { + repo.scheduleNow { + trySendBlocking(ChildEvent.Moved(snapshot, previousChildName)) + } + } + + override fun onCancelled(error: DatabaseError) { + cancel(message = "Error getting Query childEvent", cause = error.toException()) + } + }) + awaitClose { removeEventListener(listener) } + } + internal const val LIBRARY_NAME: String = "fire-db-ktx" /** @suppress */ diff --git a/firebase-database/src/main/java/com/google/firebase/database/DatabaseRegistrar.java b/firebase-database/src/main/java/com/google/firebase/database/DatabaseRegistrar.java index 7827118aa1c..1ddbf3ae9df 100644 --- a/firebase-database/src/main/java/com/google/firebase/database/DatabaseRegistrar.java +++ b/firebase-database/src/main/java/com/google/firebase/database/DatabaseRegistrar.java @@ -30,10 +30,13 @@ @Keep @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class DatabaseRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-rtdb"; + @Override public List> getComponents() { return Arrays.asList( Component.builder(FirebaseDatabaseComponent.class) + .name(LIBRARY_NAME) .add(Dependency.required(FirebaseApp.class)) .add(Dependency.deferred(InternalAuthProvider.class)) .add(Dependency.deferred(InternalAppCheckTokenProvider.class)) @@ -44,6 +47,6 @@ public List> getComponents() { c.getDeferred(InternalAuthProvider.class), c.getDeferred(InternalAppCheckTokenProvider.class))) .build(), - LibraryVersionComponent.create("fire-rtdb", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/firebase-datatransport/src/main/java/com/google/firebase/datatransport/TransportRegistrar.java b/firebase-datatransport/src/main/java/com/google/firebase/datatransport/TransportRegistrar.java index 7972b411148..dd92eb0ffab 100644 --- a/firebase-datatransport/src/main/java/com/google/firebase/datatransport/TransportRegistrar.java +++ b/firebase-datatransport/src/main/java/com/google/firebase/datatransport/TransportRegistrar.java @@ -28,10 +28,13 @@ @Keep public class TransportRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-transport"; + @Override public List> getComponents() { return Arrays.asList( Component.builder(TransportFactory.class) + .name(LIBRARY_NAME) .add(Dependency.required(Context.class)) .factory( c -> { @@ -39,6 +42,6 @@ public List> getComponents() { return TransportRuntime.getInstance().newFactory(CCTDestination.LEGACY_INSTANCE); }) .build(), - LibraryVersionComponent.create("fire-transport", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/firebase-dynamic-links/CHANGELOG.md b/firebase-dynamic-links/CHANGELOG.md new file mode 100644 index 00000000000..0ada3c07f3d --- /dev/null +++ b/firebase-dynamic-links/CHANGELOG.md @@ -0,0 +1,133 @@ +# Unreleased + +# 21.1.0 +* [unchanged] Updated to accommodate the release of the updated +[ddls] Kotlin extensions library. + + +## Kotlin +The Kotlin extensions library transitively includes the updated + `firebase-dynamic-links` library. The Kotlin extensions library has the + following additional updates: + +* [feature] Firebase now supports Kotlin coroutines. + With this release, we added + [`kotlinx-coroutines-play-services`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-play-services/){: .external} + to `firebase-dynamic-links-ktx` as a transitive dependency, which exposes the + `Task.await()` suspend function to convert a + [`Task`](https://developers.google.com/android/guides/tasks) into a Kotlin + coroutine. + +# 21.0.2 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-dynamic-links` library. The Kotlin extensions library has no +additional updates. + +# 21.0.1 +* [changed] Updated dependencies of `play-services-basement`, + `play-services-base`, and `play-services-tasks` to their latest versions + (v18.0.0, v18.0.1, and v18.0.1, respectively). For more information, see the + [note](#basement18-0-0_base18-0-1_tasks18-0-1) at the top of this release + entry. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-dynamic-links` library. The Kotlin extensions library has no +additional updates. + +# 21.0.0 +- [changed] Due to its + [dependency on Google Play services](/docs/android/android-play-services), + this SDK now requires devices and emulators to target API level 19 (KitKat) + or higher and to use Android 4.4 or higher. + +- [fixed] Fixed non-null annotation. + #2336 + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-dynamic-links` library. The Kotlin extensions library has no +additional updates. + +# 20.1.1 +- [changed] Internal infrastructure improvements. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-dynamic-links` library. The Kotlin extensions library has no +additional updates. + +# 20.1.0 +- [feature] Added `getUtmParameters` method to `PendingDynamicLinkData`. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-dynamic-links` library. The Kotlin extensions library has no +additional updates. + +# 20.0.0 +- [changed] Internal infrastructure improvements. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-dynamic-links` library. The Kotlin extensions library has no +additional updates. + +# 19.1.1 +- [changed] Updated to support improvements in the KTX library (see below). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-storage` library and has the following additional updates: + +- [feature] Added API support for destructuring of + [`ShortDynamicLink`](/docs/reference/kotlin/com/google/firebase/dynamiclinks/ShortDynamicLink) + and + [`PendingDynamicLinkData`](/docs/reference/kotlin/com/google/firebase/dynamiclinks/PendingDynamicLinkData). + +# 19.1.0 +* [feature] Added new getter methods to + [`DynamicLink.Builder`](//firebase.google.com/docs/reference/android/com/google/firebase/dynamiclinks/DynamicLink.Builder) + to improve Kotlin interop. + + +## Kotlin +* [feature] The beta release of a [ddls] Android library with + Kotlin extensions is now available. The Kotlin extensions library transitively + includes the base `firebase-dynamic-links` library. To learn more, visit the + [[ddls] KTX documentation](/docs/reference/kotlin/com/google/firebase/dynamiclinks/ktx/package-summary). + +# 19.0.0 +* [changed] Versioned to add nullability annotations to improve the Kotlin + developer experience. No other changes. + +# 16.2.0 +* [changed] Refactored code to ensure functionality alignment with other + updated Firebase libraries. + +* [changed] Updated minSdkVersion to API level 16. + +# 16.1.7 +* Internal refactor. + + +# 16.1.3 +* [fixed] Fixed an issue that caused short link creation to fail when creating +links through `FirebaseDynamicLinks.getInstance().createDynamicLink().buildShortDynamicLink()` +using Google Play Services 13.2.80 and FDL SDK 16.1.0. The issue only occurred +when creating shortening links from parameters, links created using +preconstructed long links from `setLongLink()` were unaffected. This fix also +addresses issues in newer versions of Google Play Services. + + diff --git a/firebase-dynamic-links/src/main/java/com/google/firebase/dynamiclinks/internal/FirebaseDynamicLinkRegistrar.java b/firebase-dynamic-links/src/main/java/com/google/firebase/dynamiclinks/internal/FirebaseDynamicLinkRegistrar.java index c88adb9c821..d63fdce1b53 100644 --- a/firebase-dynamic-links/src/main/java/com/google/firebase/dynamiclinks/internal/FirebaseDynamicLinkRegistrar.java +++ b/firebase-dynamic-links/src/main/java/com/google/firebase/dynamiclinks/internal/FirebaseDynamicLinkRegistrar.java @@ -37,12 +37,14 @@ @KeepForSdk @Keep public final class FirebaseDynamicLinkRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-dl"; @Override @Keep public List> getComponents() { Component firebaseDynamicLinks = Component.builder(FirebaseDynamicLinks.class) + .name(LIBRARY_NAME) .add(Dependency.required(FirebaseApp.class)) .add(Dependency.optionalProvider(AnalyticsConnector.class)) .factory( @@ -53,6 +55,7 @@ public List> getComponents() { .build(); // no need for eager init for the Internal component. return Arrays.asList( - firebaseDynamicLinks, LibraryVersionComponent.create("fire-dl", BuildConfig.VERSION_NAME)); + firebaseDynamicLinks, + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/firebase-firestore/CHANGELOG.md b/firebase-firestore/CHANGELOG.md index fbe940ff32b..62e9b05b3d5 100644 --- a/firebase-firestore/CHANGELOG.md +++ b/firebase-firestore/CHANGELOG.md @@ -1,353 +1,725 @@ -Android changes are not released automatically. Ensure that changes are released -by opting into a release at -[go/firebase-android-release](http:go/firebase-android-release) (Googlers only). - # Unreleased -- [fixed] Fixed an issue `waitForPendingWrites()` could lead to NullPointerException. + +# 24.4.0 +* [unchanged] Updated to accommodate the release of the updated + [firestore] Kotlin extensions library. + + +## Kotlin +The Kotlin extensions library transitively includes the updated + `firebase-firestore` library. The Kotlin extensions library has the following + additional updates: + +* [feature] Firebase now supports Kotlin coroutines. + With this release, we added + [`kotlinx-coroutines-play-services`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-play-services/){: .external} + to `firebase-firestore-ktx` as a transitive dependency, which exposes the + `Task.await()` suspend function to convert a + [`Task`](https://developers.google.com/android/guides/tasks) into a Kotlin + coroutine. + +# 24.3.1 +* [changed] Updated dependency of `io.grpc.*` to its latest + version (v1.48.1). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. + +# 24.3.0 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library also has the +following additional updates: + +* [feature] Added + [`Query.snapshots()`](/docs/reference/kotlin/com/google/firebase/firestore/ktx/package-summary#snapshots_1) + and + [`DocumentReference.snapshots()`](/docs/reference/kotlin/com/google/firebase/firestore/ktx/package-summary#snapshots) + Kotlin Flows to listen for realtime updates. + +# 24.2.2 +- [fixed] Fixed an issue in `waitForPendingWrites()` that could lead to a + `NullPointerException`. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. +# 24.2.1 +- [changed] Internal refactor and test improvements. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 24.2.0 -- [feature] Added `TransactionOptions` to control how many times a transaction - will retry commits before failing. - +- [feature] Added customization support for + [`FirebaseFirestore.runTransaction`](/docs/reference/android/com/google/firebase/firestore/FirebaseFirestore#runTransaction(com.google.firebase.firestore.Transaction.Function%3CTResult%3E)). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + # 24.1.2 -- [fixed] Fixed an issue where patching multiple fields shadows each other (#3528). +- [fixed] Fixed an issue where patching multiple fields shadows each other. + (#3528). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 24.1.1 -- [fixed] Fixed an issue in the experimental index engine that might have - caused Firestore to exclude document results for limit queries with local +- [fixed] Fixed an issue in the beta version of the index engine that might + cause [firestore] to exclude document results for limit queries with local modifications. -- [changed] Firestore can now serialize Objects with `android.net.Uri`s. + +- [changed] [firestore] can now serialize objects with `android.net.Uri`s. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 24.1.0 -- [feature] Added experimental support for indexed query execution. Indexes can - be enabled by invoking `FirebaseFirestore.setIndexConfiguration()` with the - JSON index definition exported by the Firestore CLI. Queries against the - cache are executed using an index once the asynchronous operation to generate - the index entries completes. -- [fixed] Fixed missing document fields issue with offline overlays (#3528) +- [feature] Added beta support for indexed query execution. You can + enable indexes by invoking `FirebaseFirestore.setIndexConfiguration()` with + the JSON index definition exported by the [firebase_cli]. Queries against + the cache are executed using an index once the asynchronous index generation + completes. + +- [fixed] Fixed missing document fields issue with offline overlays. + (#3528). + + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 24.0.2 -- [fixed] Fixed an issue of long grpc reconnection period, when App moves to - foreground after staying in background for a while. -- [fixed] Fixed an AppCheck issue that caused Firestore listeners to stop - working and receive a "Permission Denied" error. This issue only occurred for - AppCheck users that set their expiration time to under an hour. -- [fixed] Fixed a potential problem during Firestore's shutdown that prevented - the shutdown from proceeding if a network connection was opened right before. -- [changed] Queries are now send to the backend before the SDK starts local - processing, which reduces overall Query latency. -- [fixed] Fixed a NPE issue where mutations with multiple documents are not - handled correctly during previous mutation acknowledgement(#3490). +- [fixed] Fixed a [firebase_app_check] issue that caused [firestore] + listeners to stop working and receive a `Permission Denied` error. This issue + only occurred if the [app_check] expiration time was set to under an hour. + +- [fixed] Fixed a potential problem during the shutdown of [firestore] that + prevented the shutdown from proceeding if a network connection was opened + right before. + +- [fixed] Fixed an NPE issue where mutations with multiple documents were not + handled correctly during previous mutation acknowledgement. + (#3490). + +- [changed] Queries are now sent to the backend before the SDK starts local + processing, which reduces overall query latency. + +- [changed] Updated dependencies of `play-services-basement`, + `play-services-base`, and `play-services-tasks` to their latest versions + (v18.0.0, v18.0.1, and v18.0.1, respectively). For more information, see the + [note](#basement18-0-0_base18-0-1_tasks18-0-1) at the top of this release + entry. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 24.0.1 -- [changed] Improved performance for databases that contain many document - updates that have not yet been synced with the backend. -- [changed] Improved performance for queries against collections that contain +- [changed] Optimized performance for offline usage. + +- [changed] Optimized performance for queries with collections that contain subcollections. -- [fixed] Fixed an issue that can result in incomplete Query snapshots when an - app is backgrounded during query execution. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 24.0.0 -- [feature] Added support for Firebase AppCheck. +- [changed] This SDK now requires devices and emulators to target API level + 19 (KitKat) or higher and to use Android 4.4 or higher. This is due to an + update in its gRPC dependency version and to align with requirements of other + Firebase libraries. + +- [feature] Added support for [firebase_app_check]. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 23.0.4 - [fixed] Fixed an issue where some fields were missed when copying in the `FirebaseFirestoreSettings.Builder` copy constructor. + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + # 23.0.3 -- [fixed] Fixed an issue when loading a data bundle with - multi-byte Unicode characters leads to failures. +- [fixed] Fixed an issue that was causing failures when a data bundle with + multi-byte Unicode characters was loaded. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 23.0.2 -- [changed] Increases the aggressiveness of network retries when an app's - foreground status changes. +- [changed] Improved Firestore's network condition detection. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 23.0.1 - [changed] The SDK now tries to immediately establish a connection to the backend when the app enters the foreground. - + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + # 23.0.0 - - [changed] Internal infrastructure improvements. - - [changed] Internal changes to support dynamic feature modules. +- [changed] Internal infrastructure improvements. + +- [changed] Internal changes to support dynamic feature modules. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + +# 22.1.2 +* [changed] Internal changes in preparation for future support of + dynamic feature modules. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 22.1.1 -- [fixed] Fixed an issue that dropped the limit for queries loaded from - Bundles that were generated by the NodeJS SDK. -- [fixed] Fixed a Firestore bug where local cache inconsistencies were - unnecessarily being resolved, causing the `Task` objects returned from `get()` - invocations to never complete (#2404). +* [fixed] Fixed an issue that dropped the limit for queries loaded from + [firestore] bundles that were generated by the NodeJS SDK. +* [fixed] Fixed a bug where local cache inconsistencies were unnecessarily + being resolved, causing the `Task` objects returned from `get()` + invocations to never complete. + #2404 + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 22.1.0 -- [feature] Added support for Firestore Bundles via - `FirebaseFirestore.loadBundle()` and `FirebaseFirestore.getNamedQuery()`. - Bundles contain pre-packaged data produced with the NodeJS Server SDK and - can be used to populate Firestore's cache without reading documents from - the backend. - -# (22.0.2) -- [changed] A write to a document that contains FieldValue transforms is no - longer split up into two separate operations. This reduces the number of - writes the backend performs and allows each WriteBatch to hold 500 writes - regardless of how many FieldValue transformations are attached. - -# (22.0.1) -- [fixed] Removed excess validation of null and NaN values in query filters. - This more closely aligns the SDK with the Firestore backend, which has always - accepted null and NaN for all operators, even though this isn't necessarily - useful. - -# (22.0.0) -- [changed] Removed the deprecated `timestampsInSnapshotsEnabled` setting. - Any timestamps in Firestore documents are now returned as `Timestamps`. To - convert `Timestamp` classed to `java.util.Date`, use `Timestamp.toDate()`. - -# 21.6.1 -- [changed] Added new internal HTTP headers to the gRPC connection. +* [feature] Added support for [firestore] bundles via + [`FirebaseFirestore.loadBundle()`](/docs/reference/android/com/google/firebase/firestore/FirebaseFirestore#loadBundle(java.nio.ByteBuffer)) + and + [`FirebaseFirestore.getNamedQuery()`](/docs/reference/android/com/google/firebase/firestore/FirebaseFirestore#getNamedQuery(java.lang.String)). + Bundles contain pre-packaged data produced with the Firebase Admin Node.js SDK + and can be used to populate the cache for [firestore] without the need to + read documents from the backend. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + +# 22.0.2 +* [changed] A write to a document that contains `FieldValue` transforms is no + longer split into two separate operations. This reduces the number of writes + that the backend performs and allows each `WriteBatch` to hold 500 writes + regardless of how many `FieldValue` transformations are attached. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + +# 22.0.1 +* [changed] Removed excess validation of null and NaN values in query filters. + This more closely aligns the SDK with the [firestore] backend, which has + always accepted null and NaN for all operators. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + +# 22.0.0 +* [changed] Removed the deprecated `timestampsInSnapshotsEnabled` setting. + Any timestamp in a [firestore] document is now returned as a `Timestamp`. To + convert `Timestamp` classes to `java.util.Date`, use + [`Timestamp.toDate()`](/docs/reference/android/com/google/firebase/Timestamp#toDate()). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + +# 21.7.1 +* [changed] Added new internal HTTP headers to the gRPC connection. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + +# 21.7.0 +* [feature] Added + [`Query.whereNotIn()`](/docs/reference/android/com/google/firebase/firestore/Query#whereNotIn(java.lang.String,%20java.util.List)) + and + [`Query.whereNotEqualTo()`](/docs/reference/android/com/google/firebase/firestore/Query#whereNotEqualTo(java.lang.String,%20java.lang.Object)) + query operators. + + * `Query.whereNotIn()` finds documents where a specified field's value is + not in a specified array. + * `Query.whereNotEqualTo()` finds documents where a specified field's value + does not equal the specified value. + + Neither query operator finds documents where the specified field isn't + present. + +* [fixed] Fixed an issue that caused poor performance for queries that + filtered results using nested array values. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 21.6.0 -- [fixed] Removed a delay that may have prevented Firestore from immediately - reestablishing a network connection if a connectivity change occurred while - the app was in the background. -- [fixed] Fixed an issue that may have prevented the client from connecting +* [fixed] Removed a delay that may have prevented [firestore] from + immediately reestablishing a network connection if a connectivity change + occurred while the app was in the background. + +* [fixed] Fixed an issue that may have prevented the client from connecting to the backend immediately after a user signed in. -- [feature] Cloud Firestore now supports connecting to a local emulator via - `FirebaseFirestore#useEmulator()` -- [feature] Added `Query.whereNotIn()` and `Query.whereNotEqualTo()` query - operators. `Query.whereNotIn()` finds documents where a specified field’s - value is not in a specified array. `Query.whereNotEqualTo()` finds - documents where a specified field's value does not equal the specified value. - Neither query operator will match documents where the specified field is not - present. + +* [feature] Added support for connecting to the Firebase Emulator Suite via + a new method, + [`FirebaseFirestore#useEmulator()`](/docs/reference/android/com/google/firebase/firestore/FirebaseFirestore#useEmulator(java.lang.String,%20int)). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + +# 21.5.0 +* [changed] Updated the protocol buffer dependency to the newer + `protobuf-javalite` artifact. The new artifact is incompatible with the old + one, so this library needed to be upgraded to avoid conflicts. + No developer action is necessary. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 21.4.3 -- [changed] Firestore now limits the number of concurrent document lookups it - will perform when resolving inconsistencies in the local cache (#1374). +- [changed] [firestore] now limits the number of concurrent document lookups + it will perform when resolving inconsistencies in the local cache. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 21.4.2 - [changed] Removed Guava dependency from the SDK. This change is the first step in eliminating crashes caused by apps that depend on the wrong flavor of - Guava (#1125). + Guava. ([Issue #1125](//github.com/firebase/firebase-android-sdk/issues/1125)) + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 21.4.1 - [fixed] Fixed a performance regression introduced by the addition of - `Query.limitToLast(n: long)` in Firestore 23.3.1. -- [changed] Changed the in-memory representation of Firestore documents to - reduce memory allocations and improve performance. Calls to + `Query.limitToLast(n: long)` in [firestore] v21.3.1. +- [changed] Changed the in-memory representation of [firestore] documents to + reduce memory allocations and improve performance. Calls to `DocumentSnapshot.getData()` and `DocumentSnapshot.toObject()` will see the biggest improvement. + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + # 21.4.0 -- [feature] Firestore previously required that every document read in a +- [feature] Cloud Firestore previously required that every document read in a transaction must also be written. This requirement has been removed, and you can now read a document in a transaction without writing to it. -- [changed] Firestore now recovers more quickly once connections suffering - packet loss return to normal. +- [changed] Cloud Firestore now recovers more quickly when connections + suffering packet loss return to normal. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 21.3.1 - [feature] Added `Query.limitToLast(n: long)`, which returns the last `n` documents as the result. + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + # 21.3.0 - [feature] Added `Query.whereIn()` and `Query.whereArrayContainsAny()` query operators. `Query.whereIn()` finds documents where a specified field’s value is IN a specified array. `Query.whereArrayContainsAny()` finds documents where a specified field is an array and contains ANY element of a specified array. + - [changed] Improved the performance of repeatedly executed queries. Recently executed queries should see dramatic improvements. This benefit is reduced if changes accumulate while the query is inactive. Queries that use the `limit()` API may not always benefit, depending on the accumulated changes. + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + # 21.2.1 -- [fixed] Fixed an issue where Android API level 19 and earlier devices would - crash when unable to connect to Firestore (#904). -- [fixed] Fixed a race condition in Documents where access to getData and - getField on the same document in different threads could cause a - NullPointerException. -- [fixed] Fix a race condition that could cause a `NullPointerException` during - client initialization. +- [fixed] Fixed an issue where devices targeting Android API level 19 or + earlier would crash when they were unable to connect to [firestore]. + +- [fixed] Fixed a race condition in Documents where access to `getData` and + `getField` on the same document in different threads could cause a + `NullPointerException`. + +- [fixed] Fixed a race condition that could cause a `NullPointerException` + during client initialization. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 21.2.0 -- [feature] Added an `addSnapshotsInSyncListener()` method to - `FirebaseFirestore`that notifies you when all your snapshot listeners are +- [feature] Added an [`addSnapshotsInSyncListener()`](/docs/reference/android/com/google/firebase/firestore/FirebaseFirestore#addSnapshotsInSyncListener(java.lang.Runnable)) method to + `FirebaseFirestore` that notifies you when all your snapshot listeners are in sync with each other. -# 21.1.2 -- [fixed] Fixed a crash that could occur when a large number of documents were - removed during garbage collection of the persistence cache. + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 21.1.1 -- [fixed] Addressed a regression in 21.1.0 that caused the crash: "Cannot add +- [fixed] Addressed a regression in v21.1.0 that caused the crash: "Cannot add document to the RemoteDocumentCache with a read time of zero". + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + # 21.1.0 -- [feature] Added a `terminate()` method to `FirebaseFirestore` which - terminates the instance, releasing any held resources. Once it completes, you - can optionally call `clearPersistence()` to wipe persisted Firestore data from - disk. -- [feature] Added a `waitForPendingWrites()` method to `FirebaseFirestore` - which allows users to wait on a promise that resolves when all pending writes - are acknowledged by the Firestore backend. -- [changed] Transactions now perform exponential backoff before retrying. This - means transactions on highly contended documents are more likely to succeed. +Warning: We have received reports that this **v21.1.0 release** of the Firebase +Android SDK for [firestore] can trigger an uncaught exception. Make sure to +update to the next version of the Cloud Firestore SDK to get the fix. + +- [feature] Added a + [`FirebaseFirestore.terminate()`](/docs/reference/android/com/google/firebase/firestore/FirebaseFirestore#terminate()) + method which terminates the instance, releasing any held resources. Once it + completes, you can optionally call `clearPersistence()` to wipe persisted + [firestore] data from disk. + +- [feature] Added a + [`FirebaseFirestore.waitForPendingWrites()`](/docs/reference/android/com/google/firebase/firestore/FirebaseFirestore#waitForPendingWrites()) + method which allows users to wait on a promise that resolves when all pending + writes are acknowledged by the [firestore] backend. + +- [changed] Transactions now perform exponential backoff before retrying. + This means transactions on highly contended documents are more likely to + succeed. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 21.0.0 - [changed] Transactions are now more flexible. Some sequences of operations that were previously incorrectly disallowed are now allowed. For example, after reading a document that doesn't exist, you can now set it multiple times successfully in a transaction. -- [fixed] Fixed an issue where query results were temporarily missing documents - that previously had not matched but had been updated to now match the - query (#155). + +- [fixed] Fixed an issue where query results were temporarily missing + documents that previously had not matched but had been updated to now match + the query. Refer to this + [GitHub issue](https://github.com/firebase/firebase-android-sdk/issues/155) + for more details. + +* [changed] Added nullability annotations to improve the Kotlin developer + experience. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 20.2.0 - [feature] Added a `@DocumentId` annotation which can be used on a `DocumentReference` or `String` property in a POJO to indicate that the SDK should automatically populate it with the document's ID. -- [fixed] Fixed an internal assertion that was triggered when an update - with a `FieldValue.serverTimestamp()` and an update with a - `FieldValue.increment()` were pending for the same document (#491). + +- [fixed] Fixed an internal assertion that was triggered when an update with + a `FieldValue.serverTimestamp()` and an update with a + `FieldValue.increment()` were pending for the same document. Refer to this + [GitHub issue](https://github.com/firebase/firebase-android-sdk/issues/491) + for more details. + - [changed] Improved performance of queries with large result sets. + - [changed] Improved performance for queries with filters that only return a small subset of the documents in a collection. -- [changed] Instead of failing silently, Firestore now crashes the client app - if it fails to load SSL Ciphers. To avoid these crashes, you must bundle + +- [changed] Instead of failing silently, [firestore] now crashes the client + app if it fails to load SSL Ciphers. To avoid these crashes, you must bundle Conscrypt to support non-GMSCore devices on Android API level 19 (KitKat) or earlier (for more information, refer to - https://github.com/grpc/grpc-java/blob/master/SECURITY.md#tls-on-android). -- [changed] Failed transactions now fail with the exception from the last - attempt instead of always failing with an exception with code `ABORTED`. + [TLS on Android](https://github.com/grpc/grpc-java/blob/master/SECURITY.md#tls-on-android)). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 20.1.0 -- [changed] SSL and gRPC initialization now happens on a separate thread, which - reduces the time taken to produce the first query result. -- [feature] Added `clearPersistence()`, which clears the persistent storage +* [changed] SSL and gRPC initialization now happens on a separate thread, + which reduces the time taken to produce the first query result. +* [feature] Added `clearPersistence()`, which clears the persistent storage including pending writes and cached documents. This is intended to help - write reliable tests (https://github.com/firebase/firebase-js-sdk/issues/449). + write reliable tests. Refer to this + [GitHub issue](https://github.com/firebase/firebase-js-sdk/issues/449) for + more details. + -# 20.0.0 -- [changed] Migrated from the Android Support Libraries to the Jetpack - (AndroidX) Libraries. +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 19.0.2 -- [fixed] Updated gRPC to 1.21.0. A bug in the prior version would occasionally - cause a crash if a network state change occurred concurrently with an RPC. - (#428) +* [fixed] Updated gRPC to 1.21.0. A bug in the prior version would + occasionally cause a crash if a network state change occurred concurrently + with an RPC. Refer to + [GitHub issue #428](https://github.com/firebase/firebase-android-sdk/issues/428) + for more details. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 19.0.1 -- [fixed] Fixed an issue that prevented schema migrations for clients with - large offline datasets (#370). +* [fixed] Fixed an issue that prevented schema migrations for clients with + large offline datasets. Refer to this + [GitHub issue](https://github.com/firebase/firebase-android-sdk/issues/370) + for more details. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. # 19.0.0 -- [feature] You can now query across all collections in your database with a - given collection ID using the `FirebaseFirestore.collectionGroup()` method. -- [changed] The garbage collection process for on-disk persistence that +* [feature] You can now query across all collections in your database with a + given collection ID using the + [`FirebaseFirestore.collectionGroup()`](/docs/reference/android/com/google/firebase/firestore/FirebaseFirestore#collectionGroup) + method. +* [changed] The garbage collection process for on-disk persistence that removes older documents is now enabled by default. The SDK will attempt to periodically clean up older, unused documents once the on-disk cache passes a - threshold size (default: 100 MB). This threshold can be configured by setting - `FirebaseFirestoreSettings.Builder.setCacheSizeBytes`. It must be set to a - minimum of 1 MB. The garbage collection process can be disabled entirely by - setting `FirebaseFirestoreSettings.setCacheSizeBytes` to - `FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED`. + threshold size (default: 100 MB). See + [Configure cache size](/docs/firestore/manage-data/enable-offline#configure_cache_size) + for details on how to configure this. +* [changed] Internal changes that rely on an updated API to obtain + authentication credentials. If you use [firebase_auth], update to + `firebase-auth` v17.0.0 or later to ensure functionality alignment. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-firestore` library. The Kotlin extensions library has no additional +updates. + +# 18.2.0 +- [unchanged] No changes to the base `firebase-firestore` library. + + +## Kotlin +* [feature] The beta release of a [firestore] Android library with Kotlin + extensions is now available. The Kotlin extensions library transitively + includes the base `firebase-firestore` library. To learn more, visit the + [[firestore] KTX documentation](/docs/reference/kotlin/com/google/firebase/firestore/ktx/package-summary). # 18.2.0 -- [feature] Added `FieldValue.increment()`, which can be used in `update()` and - `set(..., SetOptions.merge())` to increment or decrement numeric field values - safely without transactions. -- [feature] Added functional interface `FirebaseFirestore.runBatch()`, similar - to `FirebaseFirestore.runTransaction()`, which allows a developer to focus on - the mutations of the batch rather than on creating and committing the batch. -- [changed] Prepared the persistence layer to support collection group queries. - While this feature is not yet available, all schema changes are included in - this release. -- [changed] Added `@RestrictTo` annotations to discourage the use of APIs that +* [feature] Added [`FieldValue.increment()`](/docs/reference/android/com/google/firebase/firestore/FieldValue#increment(double)), + which can be used in `update()` and `set(..., SetOptions.merge())` to + increment or decrement numeric field values safely without transactions. + +* [feature] Added functional interface [`FirebaseFirestore.runBatch()`](/docs/reference/android/com/google/firebase/firestore/FirebaseFirestore#runBatch( com.google.firebase.firestore.WriteBatch.Function)), + similar to [`FirebaseFirestore.runTransaction()`](/docs/reference/android/com/google/firebase/firestore/FirebaseFirestore#runTransaction(com.google.firebase.firestore.Transaction.Function%3CTResult%3E )), + which allows a developer to focus on the mutations of the batch rather than on + creating and committing the batch. + +* [changed] Prepared the persistence layer to support collection group + queries. While this feature is not yet available, all schema changes are + included in this release. + +* [changed] Added `@RestrictTo` annotations to discourage the use of APIs that are not public. This affects internal APIs that were previously obfuscated and are not mentioned in our documentation. -- [changed] Improved error messages for certain Number types that are not - supported by our serialization layer (#272). + +* [changed] Improved error messages for certain Number types that are not + supported by our serialization layer. # 18.1.0 -- [changed] Internal changes to ensure functionality alignment with other SDK +* [changed] Internal changes to ensure functionality alignment with other SDK releases. -- [fixed] Fixed calculation of SQLite database size on Android 9 Pie devices. +* [fixed] Fixed calculation of SQLite database size on Android 9 Pie devices. On these devices, the previous method sometimes incorrectly calculated the size by a few MBs, potentially delaying garbage collection. # 18.0.1 -- [fixed] Fixed an issue where Firestore would crash if handling write batches - larger than 2 MB in size (#208). -- [changed] Firestore now recovers more quickly from long periods without - network access (#217). +* [fixed] Fixed an issue where [firestore] would crash if handling write + batches larger than 2 MB in size. +* [changed] [firestore] now recovers more quickly from long periods without + network access. # 18.0.0 -- [changed] The `timestampsInSnapshotsEnabled` setting is now enabled by - default. Timestamp fields that read from a `DocumentSnapshot` are now - returned as `Timestamp` objects instead of `Date` objects. This is a breaking - change; developers must update any code that expects to receive a `Date` - object. See https://firebase.google.com/docs/reference/android/com/google/firebase/firestore/FirebaseFirestoreSettings.Builder.html#setTimestampsInSnapshotsEnabled(boolean) for more details. -- [feature] Custom objects (POJOs) can now be passed in several ways: as a +* [changed] The `timestampsInSnapshotsEnabled` setting is now enabled by + default. Timestamp fields that read from a `DocumentSnapshot` are now returned + as `Timestamp` objects instead of `Date` objects. This is a breaking change; + developers must update any code that expects to receive a `Date` object. See + [`FirebaseFirestoreSettings.Builder.setTimestampsInSnapshotsEnabled()`](/docs/reference/android/com/google/firebase/firestore/FirebaseFirestoreSettings.Builder.html#setTimestampsInSnapshotsEnabled(boolean)) + for more details. +* [feature] Custom objects (POJOs) can now be passed in several ways: as a field value in `update()`, within `Map<>` objects passed to `set()`, in array transform operations, and in query filters. -- [feature] `DocumentSnapshot.get()` now supports retrieving fields as - custom objects (POJOs) by passing a `Class` instance, e.g., +* [feature] `DocumentSnapshot.get()` now supports retrieving fields as custom + objects (POJOs) by passing a `Class` instance, e.g., `snapshot.get("field", CustomType.class)`. -- [fixed] Fixed an issue where if an app sent a write to the server, but the +* [fixed] Fixed an issue where if an app sent a write to the server, but the app was shut down before a listener received the write, the app could crash. # 17.1.5 -- [changed] Firestore now recovers more quickly from bad network states. -- [changed] Improved performance for reading large collections. -- [fixed] Offline persistence now properly records schema downgrades. This is a - forward-looking change that allows you to safely downgrade from future SDK +* [changed] [firestore] now recovers more quickly from bad network states. +* [changed] Improved performance for reading large collections. +* [fixed] Offline persistence now properly records schema downgrades. This is + a forward-looking change that allows you to safely downgrade from future SDK versions to this version (v17.1.5). You can already safely downgrade versions now depending on the source version. For example, you can safely downgrade from v17.1.4 to v17.1.2 because there are no schema changes between those - versions. (#134) + versions. Related: + https://github.com/firebase/firebase-android-sdk/issues/134 # 17.1.4 -- [fixed] Fixed a SQLite transaction handling issue that occasionally masked +* [fixed] Fixed a SQLite transaction-handling issue that occasionally masked exceptions when Firestore closed a transaction that was never started. For - more information, see the issue report in GitHub (https://github.com/firebase/firebase-android-sdk/issues/115). -- [fixed] Fixed a race condition that caused a `SQLiteDatabaseLockedException` + more information, see the [issue report in GitHub](https://github.com/firebase/firebase-android-sdk/issues/115). +* [fixed] Fixed a race condition that caused a `SQLiteDatabaseLockedException` when an app attempted to access the SQLite database from multiple threads. + # 17.1.2 -- [changed] Changed how the SDK handles locally-updated documents while syncing - those updates with Cloud Firestore servers. This can lead to slight behavior - changes and may affect the `SnapshotMetadata.hasPendingWrites()` metadata - flag. -- [changed] Eliminated superfluous update events for locally cached documents - that are known to lag behind the server version. Instead, the SDK buffers - these events until the client has caught up with the server. +* [changed] Changed how the SDK handles locally-updated documents while syncing those updates with Cloud Firestore servers. This can lead to slight behavior changes and may affect the [`SnapshotMetadata.hasPendingWrites()`](/docs/reference/android/com/google/firebase/firestore/SnapshotMetadata.html#hasPendingWrites()) metadata flag. +* [changed] Eliminated superfluous update events for locally cached documents that are known to lag behind the server version. Instead, the SDK buffers these events until the client has caught up with the server. # 17.1.1 -- [fixed] Fixed an issue where the first `get()` call made after being offline - could incorrectly return cached data without attempting to reach the backend. -- [changed] Changed `get()` to only make one attempt to reach the backend before - returning cached data, potentially reducing delays while offline. -- [fixed] Fixed an issue that caused Firebase to drop empty objects from calls - to `set(..., SetOptions.merge())`. -- [fixed] Updated printf-style templates to ensure that they're compile time - constants. Previously, some were influenced by error messages. When those - error messages contained `%p` or other, related tokens, `String.format()` - would throw an exception. -- [changed] Some SDK errors that represent common mistakes, like permission - errors or missing indexes, are automatically be logged as warnings in addition - to being surfaced via the API. +* [fixed] Fixed an issue where the first `get()` call made after being offline could incorrectly return cached data without attempting to reach the backend. +* [changed] Changed `get()` to only make one attempt to reach the backend before returning cached data, potentially reducing delays while offline. +* [fixed] Fixed an issue that caused Firebase to drop empty objects from calls to `set(..., SetOptions.merge())`. +* [fixed] Updated printf-style templates to ensure that they're compile time constants. Previously, some were influenced by error messages. When those error messages contained `%p` or other, related tokens, `String.format()` would throw an exception. +* [changed] Some SDK errors that represent common mistakes, like permission errors or missing indexes, are automatically logged as warnings in addition to being surfaced via the API. # 17.1.0 -- [feature] Added `FieldValue.arrayUnion()` and `FieldValue.arrayRemove()` to - atomically add and remove elements from an array field in a document. -- [feature] Added `Query.whereArrayContains()` query operator to find documents - where an array field contains a specific element. +* [fixed] Corrected an issue with methods in the Cloud Firestore v17.0.5 release. To avoid potential errors, don't use v17.0.5. -# 17.0.4 -- [fixed] Fixed an issue where queries returned fewer results than they should, - caused by documents that were cached as deleted when they should not have - been (firebase/firebase-ios-sdk#1548). Some cache data is cleared and so - clients may use extra bandwidth the first time they launch with this version - of the SDK. +# 17.0.5 +* [feature] Added [`FieldValue.arrayUnion()`](/docs/reference/android/com/google/firebase/firestore/FieldValue.html#arrayUnion(Object...)) and [`FieldValue.arrayRemove()`](/docs/reference/android/com/google/firebase/firestore/FieldValue.html#arrayRemove(Object...)) to atomically add and remove elements from an array field in a document. +* [feature] Added [`Query.whereArrayContains()`](/docs/reference/android/com/google/firebase/firestore/Query.html#whereArrayContains(com.google.firebase.firestore.FieldPath, java.lang.Object)) query operator to find documents where an array field contains a specific element. +* [changed] Improved offline performance with many outstanding writes. +* [fixed] Firestore will now recover from auth token expiration when the system clock is wrong. +# 17.0.4 +* [fixed] Fixed an issue where queries returned fewer results than they + should. The issue related to + [improper caching](https://github.com/firebase/firebase-ios-sdk/issues/1548), + so clients may use extra bandwidth the first time they launch with this + version of the SDK, as they re-download cleared cached data. # 17.0.3 -- [changed] The `Timestamp` class now implements `Parcelable` in addition to - `Comparable`. +* [changed] The [`Timestamp`](/docs/reference/android/com/google/firebase/Timestamp) class now implements [`Parcelable`](//developer.android.com/reference/android/os/Parcelable) in addition to [`Comparable`](//developer.android.com/reference/java/lang/Comparable). + +# 17.0.2 +* [changed] gRPC requirement updated from 1.8.0 to 1.12.0. This allows quicker + failover between Wi-Fi and cellular networks. + +# 17.0.1 +* [fixed] Fixed an issue where `set()` didn't correctly respect + [`SetOptions.mergeFields()`](/docs/reference/android/com/google/firebase/firestore/SetOptions.html#mergeFields(java.util.List)) + for data containing + [`FieldValue.delete()`](/docs/reference/android/com/google/firebase/firestore/FieldValue.html#delete()) + or + [`FieldValue.serverTimestamp()`](/docs/reference/android/com/google/firebase/firestore/FieldValue.html#serverTimestamp()) + values. + diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index d7a43041af9..edf6c6ed73b 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -19,6 +19,20 @@ package com.google.firebase { package com.google.firebase.firestore { + public class AggregateQuery { + method @NonNull public com.google.android.gms.tasks.Task get(@NonNull com.google.firebase.firestore.AggregateSource); + method @NonNull public com.google.firebase.firestore.Query getQuery(); + } + + public class AggregateQuerySnapshot { + method public long getCount(); + method @NonNull public com.google.firebase.firestore.AggregateQuery getQuery(); + } + + public enum AggregateSource { + enum_constant public static final com.google.firebase.firestore.AggregateSource SERVER; + } + public class Blob implements java.lang.Comparable { method public int compareTo(@NonNull com.google.firebase.firestore.Blob); method @NonNull public static com.google.firebase.firestore.Blob fromBytes(@NonNull byte[]); @@ -290,6 +304,7 @@ package com.google.firebase.firestore { method @NonNull public com.google.firebase.firestore.ListenerRegistration addSnapshotListener(@NonNull com.google.firebase.firestore.MetadataChanges, @NonNull com.google.firebase.firestore.EventListener); method @NonNull public com.google.firebase.firestore.ListenerRegistration addSnapshotListener(@NonNull java.util.concurrent.Executor, @NonNull com.google.firebase.firestore.MetadataChanges, @NonNull com.google.firebase.firestore.EventListener); method @NonNull public com.google.firebase.firestore.ListenerRegistration addSnapshotListener(@NonNull android.app.Activity, @NonNull com.google.firebase.firestore.MetadataChanges, @NonNull com.google.firebase.firestore.EventListener); + method @NonNull public com.google.firebase.firestore.AggregateQuery count(); method @NonNull public com.google.firebase.firestore.Query endAt(@NonNull com.google.firebase.firestore.DocumentSnapshot); method @NonNull public com.google.firebase.firestore.Query endAt(java.lang.Object...); method @NonNull public com.google.firebase.firestore.Query endBefore(@NonNull com.google.firebase.firestore.DocumentSnapshot); diff --git a/firebase-firestore/gradle.properties b/firebase-firestore/gradle.properties index 94b255558d4..d0583730c2c 100644 --- a/firebase-firestore/gradle.properties +++ b/firebase-firestore/gradle.properties @@ -1,2 +1,2 @@ -version=24.3.1 -latestReleasedVersion=24.3.0 +version=24.3.2 +latestReleasedVersion=24.3.1 diff --git a/firebase-firestore/ktx/ktx.gradle b/firebase-firestore/ktx/ktx.gradle index a520029398a..04e58cf4d5c 100644 --- a/firebase-firestore/ktx/ktx.gradle +++ b/firebase-firestore/ktx/ktx.gradle @@ -57,7 +57,7 @@ dependencies { implementation project(':firebase-common:ktx') implementation project(':firebase-firestore') implementation 'androidx.annotation:annotation:1.1.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" implementation 'com.google.android.gms:play-services-basement:18.1.0' testImplementation project(':firebase-database-collection') testImplementation 'org.mockito:mockito-core:2.25.0' diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/CountTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/CountTest.java index 5dffb4a70c4..5636cecffdd 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/CountTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/CountTest.java @@ -30,19 +30,12 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.firebase.firestore.testutil.IntegrationTestUtil; import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class CountTest { - @Before - public void setUp() { - // TODO(b/243368243): Remove this once backend is ready to support count. - org.junit.Assume.assumeTrue(BuildConfig.USE_EMULATOR_FOR_TESTS); - } - @After public void tearDown() { IntegrationTestUtil.tearDown(); @@ -88,9 +81,8 @@ public void testCanRunCount() { "b", map("k", "b"), "c", map("k", "c"))); - AggregateQuerySnapshot snapshot = - waitFor(collection.count().get(AggregateSource.SERVER_DIRECT)); - assertEquals(Long.valueOf(3), snapshot.getCount()); + AggregateQuerySnapshot snapshot = waitFor(collection.count().get(AggregateSource.SERVER)); + assertEquals(3L, snapshot.getCount()); } @Test @@ -103,8 +95,8 @@ public void testCanRunCountWithFilters() { "c", map("k", "c"))); AggregateQuerySnapshot snapshot = - waitFor(collection.whereEqualTo("k", "b").count().get(AggregateSource.SERVER_DIRECT)); - assertEquals(Long.valueOf(1), snapshot.getCount()); + waitFor(collection.whereEqualTo("k", "b").count().get(AggregateSource.SERVER)); + assertEquals(1L, snapshot.getCount()); } @Test @@ -118,9 +110,9 @@ public void testCanRunCountWithOrderBy() { "d", map("absent", "d"))); AggregateQuerySnapshot snapshot = - waitFor(collection.orderBy("k").count().get(AggregateSource.SERVER_DIRECT)); + waitFor(collection.orderBy("k").count().get(AggregateSource.SERVER)); // "d" is filtered out because it is ordered by "k". - assertEquals(Long.valueOf(3), snapshot.getCount()); + assertEquals(3L, snapshot.getCount()); } @Test @@ -132,7 +124,7 @@ public void testTerminateDoesNotCrashWithFlyingCountQuery() { "b", map("k", "b"), "c", map("k", "c"))); - collection.orderBy("k").count().get(AggregateSource.SERVER_DIRECT); + collection.orderBy("k").count().get(AggregateSource.SERVER); waitFor(collection.firestore.terminate()); } @@ -146,15 +138,15 @@ public void testSnapshotEquals() { "c", map("k", "c"))); AggregateQuerySnapshot snapshot1 = - waitFor(collection.whereEqualTo("k", "b").count().get(AggregateSource.SERVER_DIRECT)); + waitFor(collection.whereEqualTo("k", "b").count().get(AggregateSource.SERVER)); AggregateQuerySnapshot snapshot1_same = - waitFor(collection.whereEqualTo("k", "b").count().get(AggregateSource.SERVER_DIRECT)); + waitFor(collection.whereEqualTo("k", "b").count().get(AggregateSource.SERVER)); AggregateQuerySnapshot snapshot2 = - waitFor(collection.whereEqualTo("k", "a").count().get(AggregateSource.SERVER_DIRECT)); + waitFor(collection.whereEqualTo("k", "a").count().get(AggregateSource.SERVER)); waitFor(collection.document("d").set(map("k", "a"))); AggregateQuerySnapshot snapshot2_different = - waitFor(collection.whereEqualTo("k", "a").count().get(AggregateSource.SERVER_DIRECT)); + waitFor(collection.whereEqualTo("k", "a").count().get(AggregateSource.SERVER)); assertTrue(snapshot1.equals(snapshot1_same)); assertEquals(snapshot1.hashCode(), snapshot1_same.hashCode()); @@ -196,9 +188,9 @@ public void testCanRunCollectionGroupQuery() { waitFor(batch.commit()); AggregateQuerySnapshot snapshot = - waitFor(db.collectionGroup(collectionGroup).count().get(AggregateSource.SERVER_DIRECT)); + waitFor(db.collectionGroup(collectionGroup).count().get(AggregateSource.SERVER)); assertEquals( - Long.valueOf(5), // "cg-doc1", "cg-doc2", "cg-doc3", "cg-doc4", "cg-doc5", + 5L, // "cg-doc1", "cg-doc2", "cg-doc3", "cg-doc4", "cg-doc5", snapshot.getCount()); } @@ -213,18 +205,13 @@ public void testCanRunCountWithFiltersAndLimits() { "d", map("k", "d"))); AggregateQuerySnapshot snapshot = - waitFor( - collection.whereEqualTo("k", "a").limit(2).count().get(AggregateSource.SERVER_DIRECT)); - assertEquals(Long.valueOf(2), snapshot.getCount()); + waitFor(collection.whereEqualTo("k", "a").limit(2).count().get(AggregateSource.SERVER)); + assertEquals(2L, snapshot.getCount()); snapshot = waitFor( - collection - .whereEqualTo("k", "a") - .limitToLast(2) - .count() - .get(AggregateSource.SERVER_DIRECT)); - assertEquals(Long.valueOf(2), snapshot.getCount()); + collection.whereEqualTo("k", "a").limitToLast(2).count().get(AggregateSource.SERVER)); + assertEquals(2L, snapshot.getCount()); snapshot = waitFor( @@ -232,21 +219,19 @@ public void testCanRunCountWithFiltersAndLimits() { .whereEqualTo("k", "d") .limitToLast(1000) .count() - .get(AggregateSource.SERVER_DIRECT)); - assertEquals(Long.valueOf(1), snapshot.getCount()); + .get(AggregateSource.SERVER)); + assertEquals(1L, snapshot.getCount()); } @Test public void testCanRunCountOnNonExistentCollection() { CollectionReference collection = testFirestore().collection("random-coll"); - AggregateQuerySnapshot snapshot = - waitFor(collection.count().get(AggregateSource.SERVER_DIRECT)); - assertEquals(Long.valueOf(0), snapshot.getCount()); + AggregateQuerySnapshot snapshot = waitFor(collection.count().get(AggregateSource.SERVER)); + assertEquals(0L, snapshot.getCount()); - snapshot = - waitFor(collection.whereEqualTo("k", 100).count().get(AggregateSource.SERVER_DIRECT)); - assertEquals(Long.valueOf(0), snapshot.getCount()); + snapshot = waitFor(collection.whereEqualTo("k", 100).count().get(AggregateSource.SERVER)); + assertEquals(0L, snapshot.getCount()); } @Test @@ -259,14 +244,13 @@ public void testFailWithoutNetwork() { "c", map("k", "c"))); waitFor(collection.getFirestore().disableNetwork()); - Exception e = waitForException(collection.count().get(AggregateSource.SERVER_DIRECT)); + Exception e = waitForException(collection.count().get(AggregateSource.SERVER)); assertThat(e, instanceOf(FirebaseFirestoreException.class)); assertEquals( FirebaseFirestoreException.Code.UNAVAILABLE, ((FirebaseFirestoreException) e).getCode()); waitFor(collection.getFirestore().enableNetwork()); - AggregateQuerySnapshot snapshot = - waitFor(collection.count().get(AggregateSource.SERVER_DIRECT)); - assertEquals(Long.valueOf(3), snapshot.getCount()); + AggregateQuerySnapshot snapshot = waitFor(collection.count().get(AggregateSource.SERVER)); + assertEquals(3L, snapshot.getCount()); } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateQuery.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateQuery.java index 179bc6e1b2d..cb7f1684759 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateQuery.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateQuery.java @@ -21,32 +21,31 @@ import com.google.firebase.firestore.util.Preconditions; /** - * A {@code AggregateQuery} computes some aggregation statistics from the result set of a base - * {@link Query}. + * A query that calculates aggregations over an underlying query. * *

Subclassing Note: Cloud Firestore classes are not meant to be subclassed except for use * in test mocks. Subclassing is not supported in production code and new SDK releases may break * code that does so. */ -class AggregateQuery { - // The base query. +public class AggregateQuery { + private final Query query; AggregateQuery(@NonNull Query query) { this.query = query; } - /** Returns the base {@link Query} for this aggregate query. */ + /** Returns the query whose aggregations will be calculated by this object. */ @NonNull public Query getQuery() { return query; } /** - * Executes the aggregate query and returns the results as a {@code AggregateQuerySnapshot}. + * Executes this query. * - * @param source A value to configure the get behavior. - * @return A Task that will be resolved with the results of the {@code AggregateQuery}. + * @param source The source from which to acquire the aggregate results. + * @return A {@link Task} that will be resolved with the results of the query. */ @NonNull public Task get(@NonNull AggregateSource source) { @@ -70,14 +69,35 @@ public Task get(@NonNull AggregateSource source) { return tcs.getTask(); } + /** + * Compares this object with the given object for equality. + * + *

This object is considered "equal" to the other object if and only if all of the following + * conditions are satisfied: + * + *

    + *
  1. {@code object} is a non-null instance of {@link AggregateQuery}. + *
  2. {@code object} performs the same aggregations as this {@link AggregateQuery}. + *
  3. The underlying {@link Query} of {@code object} compares equal to that of this object. + *
+ * + * @param object The object to compare to this object for equality. + * @return {@code true} if this object is "equal" to the given object, as defined above, or {@code + * false} otherwise. + */ @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof AggregateQuery)) return false; - AggregateQuery that = (AggregateQuery) o; - return query.equals(that.query); + public boolean equals(Object object) { + if (this == object) return true; + if (!(object instanceof AggregateQuery)) return false; + AggregateQuery other = (AggregateQuery) object; + return query.equals(other.query); } + /** + * Calculates and returns the hash code for this object. + * + * @return the hash code for this object. + */ @Override public int hashCode() { return query.hashCode(); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateQuerySnapshot.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateQuerySnapshot.java index 0ec69134471..2d8ee7be8f0 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateQuerySnapshot.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateQuerySnapshot.java @@ -17,17 +17,16 @@ import static com.google.firebase.firestore.util.Preconditions.checkNotNull; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import java.util.Objects; /** - * A {@code AggregateQuerySnapshot} contains results of a {@link AggregateQuery}. + * The results of executing an {@link AggregateQuery}. * *

Subclassing Note: Cloud Firestore classes are not meant to be subclassed except for use * in test mocks. Subclassing is not supported in production code and new SDK releases may break * code that does so. */ -class AggregateQuerySnapshot { +public class AggregateQuerySnapshot { private final long count; private final AggregateQuery query; @@ -38,29 +37,46 @@ class AggregateQuerySnapshot { this.count = count; } - /** @return The original {@link AggregateQuery} this snapshot is a result of. */ + /** Returns the query that was executed to produce this result. */ @NonNull public AggregateQuery getQuery() { return query; } - /** - * @return The result of a document count aggregation. Returns null if no count aggregation is - * available in the result. - */ - @Nullable - public Long getCount() { + /** Returns the number of documents in the result set of the underlying query. */ + public long getCount() { return count; } + /** + * Compares this object with the given object for equality. + * + *

This object is considered "equal" to the other object if and only if all of the following + * conditions are satisfied: + * + *

    + *
  1. {@code object} is a non-null instance of {@link AggregateQuerySnapshot}. + *
  2. The {@link AggregateQuery} of {@code object} compares equal to that of this object. + *
  3. {@code object} has the same results as this object. + *
+ * + * @param object The object to compare to this object for equality. + * @return {@code true} if this object is "equal" to the given object, as defined above, or {@code + * false} otherwise. + */ @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof AggregateQuerySnapshot)) return false; - AggregateQuerySnapshot snapshot = (AggregateQuerySnapshot) o; - return count == snapshot.count && query.equals(snapshot.query); + public boolean equals(Object object) { + if (this == object) return true; + if (!(object instanceof AggregateQuerySnapshot)) return false; + AggregateQuerySnapshot other = (AggregateQuerySnapshot) object; + return count == other.count && query.equals(other.query); } + /** + * Calculates and returns the hash code for this object. + * + * @return the hash code for this object. + */ @Override public int hashCode() { return Objects.hash(count, query); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateSource.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateSource.java index afb235df184..31402ba99e4 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateSource.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateSource.java @@ -14,13 +14,23 @@ package com.google.firebase.firestore; -/** Configures the behavior of {@link AggregateQuery#get}. */ -enum AggregateSource { +/** + * The sources from which an {@link AggregateQuery} can retrieve its results. + * + * @see AggregateQuery#get + */ +public enum AggregateSource { /** - * Reach to the Firestore backend and surface the result verbatim, that is no local documents or - * mutations in the SDK cache will be included in the surfaced result. + * Perform the aggregation on the server and download the result. * - *

Requires client to be online. + *

The result received from the server is presented, unaltered, without considering any local + * state. That is, documents in the local cache are not taken into consideration, neither are + * local modifications not yet synchronized with the server. Previously-downloaded results, if + * any, are not used: every request using this source necessarily involves a round trip to the + * server. + * + *

The {@link AggregateQuery} will fail if the server cannot be reached, such as if the client + * is offline. */ - SERVER_DIRECT, + SERVER, } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirestoreRegistrar.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirestoreRegistrar.java index 7d7b9d12e1c..2d91eeba828 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirestoreRegistrar.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirestoreRegistrar.java @@ -39,11 +39,14 @@ @Keep @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class FirestoreRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-fst"; + @Override @Keep public List> getComponents() { return Arrays.asList( Component.builder(FirestoreMultiDbComponent.class) + .name(LIBRARY_NAME) .add(Dependency.required(FirebaseApp.class)) .add(Dependency.required(Context.class)) .add(Dependency.optionalProvider(HeartBeatInfo.class)) @@ -63,6 +66,6 @@ public List> getComponents() { c.getProvider(HeartBeatInfo.class), c.get(FirebaseOptions.class)))) .build(), - LibraryVersionComponent.create("fire-fst", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Query.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/Query.java index 125b93c53a4..8db1e9ff8db 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Query.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Query.java @@ -1224,13 +1224,19 @@ private void validateHasExplicitOrderByForLimitToLast() { } /** - * Creates an {@link AggregateQuery} counting the number of documents matching this query. + * Returns a query that counts the documents in the result set of this query. * - * @return An {@link AggregateQuery} object that can be used to count the number of documents in - * the result set of this query. + *

The returned query, when executed, counts the documents in the result set of this query + * without actually downloading the documents. + * + *

Using the returned query to count the documents is efficient because only the final count, + * not the documents' data, is downloaded. The returned query can even count the documents if the + * result set would be prohibitively large to download entirely (e.g. thousands of documents). + * + * @return a query that counts the documents in the result set of this query. */ @NonNull - AggregateQuery count() { + public AggregateQuery count() { return new AggregateQuery(this); } diff --git a/firebase-functions/CHANGELOG.md b/firebase-functions/CHANGELOG.md new file mode 100644 index 00000000000..5e3bddd2072 --- /dev/null +++ b/firebase-functions/CHANGELOG.md @@ -0,0 +1,148 @@ +# Unreleased + +# 20.2.0 +* [unchanged] Updated to accommodate the release of the updated + [functions_client] Kotlin extensions library. + + +## Kotlin +The Kotlin extensions library transitively includes the updated + `firebase-functions` library. The Kotlin extensions library has the following + additional updates: + +* [feature] Firebase now supports Kotlin coroutines. + With this release, we added + [`kotlinx-coroutines-play-services`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-play-services/){: .external} + to `firebase-functions-ktx` as a transitive dependency, which exposes the + `Task.await()` suspend function to convert a + [`Task`](https://developers.google.com/android/guides/tasks) into a Kotlin + coroutine. + +# 20.1.1 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-functions` library. The Kotlin extensions library has no additional +updates. + +# 20.1.0 +- [feature] Added a new method + [`getHttpsCallableFromUrl(java.net.URL)`](/docs/reference/android/com/google/firebase/functions/FirebaseFunctions#public-httpscallablereference-gethttpscallablefromurl-url-url) + to create callables with URLs. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-functions` library. The Kotlin extensions library has no additional +updates. + +# 20.0.2 +- [changed] Updated dependencies of `play-services-basement`, + `play-services-base`, and `play-services-tasks` to their latest versions + (v18.0.0, v18.0.1, and v18.0.1, respectively). For more information, see the + [note](#basement18-0-0_base18-0-1_tasks18-0-1) at the top of this release + entry. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-functions` library. The Kotlin extensions library has no additional +updates. + +# 20.0.1 +- [fixed] Fixed an issue that prevented functions from proceeding after + [app_check] failures. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-functions` library. The Kotlin extensions library has no additional +updates. + +# 20.0.0 +- [feature] Added abuse reduction features. +- [changed] Internal changes to support dynamic feature modules. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-functions` library. The Kotlin extensions library has no additional +updates. + +# 19.2.0 +* [feature] Added support for custom domains, [`FirebaseFunctions#getInstance()`](/docs/reference/android/com/google/firebase/functions/FirebaseFunctions#getInstance(java.lang.String)). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-functions` library. The Kotlin extensions library has no additional +updates. + +# 19.1.0 +* [feature] Added support for connecting to the Firebase Emulator Suite via + a new method, + [`FirebaseFunctions#UseEmulator()`](/docs/reference/android/com/google/firebase/functions/FirebaseFunctions#useEmulator(java.lang.String,%20int)). + +* [deprecated] Deprecated the `useFunctionsEmulator(String)` method. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-functions` library. The Kotlin extensions library has no additional +updates. + +# 19.0.2 +- [changed] Internal changes to ensure functionality alignment with other SDK releases. + + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-functions` library. The Kotlin extensions library has no additional +updates. + +# 19.0.1 +* [unchanged] Updated to accommodate the release of the [functions_client] + Kotlin extensions library. + + +## Kotlin +* [feature] The beta release of a [functions_client] Android library with + Kotlin extensions is now available. The Kotlin extensions library transitively + includes the base `firebase-functions` library. To learn more, visit the + [[cloud_functions] KTX documentation](/docs/reference/kotlin/com/google/firebase/functions/ktx/package-summary). + +# 19.0.0 +* [changed] Versioned to add nullability annotations to improve the Kotlin + developer experience. No other changes. + +# 18.1.0 +* [feature] Added + [`getTimeout`](/docs/reference/android/com/google/firebase/functions/HttpsCallableReference) + method to get the timeout for a callable. For more details, refer to + [GitHub PR #574](//github.com/firebase/firebase-android-sdk/pull/574). + +# 17.0.0 +* [changed] Updated minSdkVersion to API level 16. + +# 16.3.0 +* [changed] Changed the default timeout for callable functions to 70 seconds + ([#2329](//github.com/firebase/firebase-android-sdk/pull/224)). + +* [feature] Added + [`setTimeout`](/docs/reference/android/com/google/firebase/functions/HttpsCallableReference) + and + [`withTimeout`](/docs/reference/android/com/google/firebase/functions/HttpsCallableReference) + methods to change the timeout for a callable + ([#2329](//github.com/firebase/firebase-android-sdk/pull/224)). + +# 16.1.0 +* [feature] `FirebaseFunctions.getInstance()` now allows passing in an +optional region to override the default "us-central1". + +* [feature] New `useFunctionsEmulator` method allows testing against a local +instance of the [Cloud Functions Emulator](https://firebase.google.com/docs/functions/local-emulator). + diff --git a/firebase-functions/src/main/java/com/google/firebase/functions/FunctionsRegistrar.java b/firebase-functions/src/main/java/com/google/firebase/functions/FunctionsRegistrar.java index 4a36d4ee6c9..9a1033721fb 100644 --- a/firebase-functions/src/main/java/com/google/firebase/functions/FunctionsRegistrar.java +++ b/firebase-functions/src/main/java/com/google/firebase/functions/FunctionsRegistrar.java @@ -34,6 +34,8 @@ */ @Keep public class FunctionsRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-fn"; + @Override public List> getComponents() { return Arrays.asList( @@ -49,6 +51,7 @@ public List> getComponents() { c.getDeferred(InternalAppCheckTokenProvider.class))) .build(), Component.builder(FunctionsMultiResourceComponent.class) + .name(LIBRARY_NAME) .add(Dependency.required(Context.class)) .add(Dependency.required(ContextProvider.class)) .add(Dependency.required(FirebaseApp.class)) @@ -59,6 +62,6 @@ public List> getComponents() { c.get(ContextProvider.class), c.get(FirebaseApp.class))) .build(), - LibraryVersionComponent.create("fire-fn", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/firebase-inappmessaging-display/CHANGELOG.md b/firebase-inappmessaging-display/CHANGELOG.md new file mode 100644 index 00000000000..fd24400e106 --- /dev/null +++ b/firebase-inappmessaging-display/CHANGELOG.md @@ -0,0 +1,252 @@ +# Unreleased + +# 20.2.0 +* [fixed] Fixed a bug that prevented marking more than one message as + impressed. + + +## Kotlin +The Kotlin extensions library transitively includes the updated + `firebase-inappmessaging-display` library. The Kotlin extensions library has + the following additional updates: + +* [feature] Firebase now supports Kotlin coroutines. + With this release, we added + [`kotlinx-coroutines-play-services`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-play-services/){: .external} + to `firebase-inappmessaging-display-ktx` as a transitive dependency, which + exposes the `Task.await()` suspend function to convert a + [`Task`](https://developers.google.com/android/guides/tasks) into a Kotlin + coroutine. + +# 20.1.3 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 20.1.2 +* [changed] Updated dependencies of `play-services-basement`, + `play-services-base`, and `play-services-tasks` to their latest versions + (v18.0.0, v18.0.1, and v18.0.1, respectively). For more information, see the + [note](#basement18-0-0_base18-0-1_tasks18-0-1) at the top of this release + entry. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 20.1.1 +- [changed] Updated the gRPC dependency version. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 20.1.0 +* [changed] Migrated to Glide library for image downloading. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 20.0.0 +* [changed] Internal infrastructure improvements. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 19.1.5 +* [fixed] Fixed `WindowManager$BadTokenException` when showing an in-app + message. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 19.1.4 +* [fixed] Fixed in-app message button click not working in Android 11 + because of package visibility changes. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 19.1.3 +* [changed] Internal changes to maintain compatibility with other Firebase + SDKs. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 19.1.2 +* [changed] Internal changes to maintain compatibility with other Firebase + SDKs. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 19.1.1 +* [fixed] Improved link handling on devices without any browser installed + or without Chrome installed. + +* [feature] Added the ability to register a dismiss listener that reacts to + message dismissal. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 19.1.0 +* [changed] Updated the protocol buffer dependency to the newer + `protobuf-javalite` artifact. The new artifact is incompatible with the old + one, so this library needed to be upgraded to avoid conflicts. + No developer action is necessary. + + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 19.0.7 +* [fixed] Improved handling of activity transitions. + (GitHub [Issue #1410](//github.com/firebase/firebase-android-sdk/issues/1410) + and [Issue #1092](//github.com/firebase/firebase-android-sdk/issues/1092)) + +* [changed] Migrated to use the [firebase_installations] service _directly_ + instead of using an indirect dependency via the Firebase Instance ID SDK. + + {% include "docs/reference/android/client/_includes/_iid-indirect-dependency-solutions.html" %} + + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 19.0.6 +* [fixed] Fixed issue causing apps to become unresponsive in limited network + conditions. [GitHub Issue #1430](//github.com/firebase/firebase-android-sdk/issues/1430) + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 19.0.5 +* [fixed] Fixed issue where campaigns with frequency limits were not properly + displaying multiple times. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 19.0.4 +* [fixed] Fixed issue with messages not being fetched on app first open. + +* [fixed] Fixed issue with first foreground trigger not being picked up. + + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 19.0.3 +* [changed] Internal changes to enable future SDK improvements. + + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging-display` library. The Kotlin extensions library has no +additional updates. + +# 19.0.2 +* [changed] Updated version of Dagger to 2.24. +* [fixed] Bug fixes to improve SDK stability. +* [fixed] Fixed memory leak. + + +## Kotlin +* [feature] The beta release of a [inappmessaging] Display Android library + with Kotlin extensions is now available. The Kotlin extensions library + transitively includes the base `firebase-inappmessaging-display` library. + To learn more, visit the + [[inappmessaging] Display KTX documentation](/docs/reference/kotlin/com/google/firebase/inappmessaging/display/ktx/package-summary). + +# 19.0.1 +* [changed] Internal changes to accommodate open-sourcing of the library and + to ensure functionality alignment with other SDK releases. + +# 19.0.0 +* [changed] Versioned to add nullability annotations to improve the Kotlin + developer experience. No other changes. + +# 18.0.2 +* [changed] Updated to support Picasso version 2.71828. +* [fixed] Updated to send engagement metrics via [analytics]. +* [fixed] Fixed issue with callbacks triggering for Card templates. + +# 17.2.0 +* [feature] Adds support for card in-app messages. +* [feature] Adds direct triggering (via [inappmessaging] SDK) of in-app + messages. + +# 17.1.1 +* [fixed] Fixed [firestore] and [inappmessaging] compatibility on Android + API level 19 (KitKat). The underlying issue was that [firestore] and + [cloud_functions] couldn't agree on which ciphers to use; this update fixes + this issue by overriding the set of ciphers that they use. Refer to + [GitHub issue 244](https://github.com/firebase/firebase-android-sdk/issues/244) + for more information. + +# 17.1.0 +* [feature] Adds functionality to programmatically register listeners for + updates on in-app engagement (for example, impression, click, display errors). See + [`FirebaseInAppMessaging.addClickListener()`](/docs/reference/android/com/google/firebase/inappmessaging/FirebaseInAppMessaging.addClickListener()) + for more details. + +# 17.0.5 +* [fixed] Users with restricted API keys can now use the SDK as expected. + +# 17.0.3 +* [fixed] Improved caching logic, added safeguards for cache expiration, and cleaned up API surface to prepare for open sourcing. + +# 17.0.1 +* [fixed] Fixed an issue where [fiam] and Firestore could not be included/built into the same app, because of an obfuscation collision. + +# 17.0.0 +* [feature] The initial public beta release of the Firebase In-App Messaging Display SDK for Android is now available. To learn more, see the [Firebase In-App Messaging documentation](/docs/in-app-messaging). + diff --git a/firebase-inappmessaging-display/firebase-inappmessaging-display.gradle b/firebase-inappmessaging-display/firebase-inappmessaging-display.gradle index 7e1298e32ce..66451a1c15d 100644 --- a/firebase-inappmessaging-display/firebase-inappmessaging-display.gradle +++ b/firebase-inappmessaging-display/firebase-inappmessaging-display.gradle @@ -102,6 +102,9 @@ dependencies { testImplementation 'androidx.test:core:1.2.0' testImplementation 'com.google.guava:guava:30.1-android' + androidTestImplementation project(':integ-testing') + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation "androidx.annotation:annotation:1.0.0" androidTestImplementation "org.mockito:mockito-core:2.25.0" androidTestImplementation "com.google.dexmaker:dexmaker:1.2" androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito:2.28.1" diff --git a/firebase-inappmessaging-display/src/androidTest/java/com/google/firebase/inappmessaging/display/StrictModeTest.java b/firebase-inappmessaging-display/src/androidTest/java/com/google/firebase/inappmessaging/display/StrictModeTest.java new file mode 100644 index 00000000000..ed17365f04c --- /dev/null +++ b/firebase-inappmessaging-display/src/androidTest/java/com/google/firebase/inappmessaging/display/StrictModeTest.java @@ -0,0 +1,47 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.inappmessaging.display; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions.Builder; +import com.google.firebase.iid.FirebaseInstanceId; +import com.google.firebase.inappmessaging.FirebaseInAppMessagingDisplay; +import com.google.firebase.testing.integ.StrictModeRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class StrictModeTest { + + @Rule public StrictModeRule strictMode = new StrictModeRule(); + + @Test + public void initializingFirebaseInAppMessagingDisplay_shouldNotViolateStrictMode() { + FirebaseApp app = + FirebaseApp.initializeApp( + ApplicationProvider.getApplicationContext(), + new Builder().setApiKey("api").setProjectId("123").setApplicationId("appId").build(), + "hello"); + // Don't check for violations in other erroring components + app.get(FirebaseInstanceId.class); + strictMode.runOnMainThread( + () -> { + app.get(FirebaseInAppMessagingDisplay.class); + }); + } +} diff --git a/firebase-inappmessaging-display/src/main/java/com/google/firebase/inappmessaging/display/FirebaseInAppMessagingDisplayRegistrar.java b/firebase-inappmessaging-display/src/main/java/com/google/firebase/inappmessaging/display/FirebaseInAppMessagingDisplayRegistrar.java index afae9afa942..68658e69c38 100644 --- a/firebase-inappmessaging-display/src/main/java/com/google/firebase/inappmessaging/display/FirebaseInAppMessagingDisplayRegistrar.java +++ b/firebase-inappmessaging-display/src/main/java/com/google/firebase/inappmessaging/display/FirebaseInAppMessagingDisplayRegistrar.java @@ -39,17 +39,20 @@ */ @Keep public class FirebaseInAppMessagingDisplayRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-fiamd"; + @Override @Keep public List> getComponents() { return Arrays.asList( Component.builder(FirebaseInAppMessagingDisplay.class) + .name(LIBRARY_NAME) .add(Dependency.required(FirebaseApp.class)) .add(Dependency.required(FirebaseInAppMessaging.class)) .factory(this::buildFirebaseInAppMessagingUI) .eagerInDefaultApp() .build(), - LibraryVersionComponent.create("fire-fiamd", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } private FirebaseInAppMessagingDisplay buildFirebaseInAppMessagingUI( diff --git a/firebase-inappmessaging/CHANGELOG.md b/firebase-inappmessaging/CHANGELOG.md new file mode 100644 index 00000000000..cae4757c2ee --- /dev/null +++ b/firebase-inappmessaging/CHANGELOG.md @@ -0,0 +1,252 @@ +# Unreleased + +# 20.2.0 +* [fixed] Fixed a bug that prevented marking more than one message as + impressed. + + +## Kotlin +The Kotlin extensions library transitively includes the updated + `firebase-inappmessaging` library. The Kotlin extensions library has the + following additional updates: + +* [feature] Firebase now supports Kotlin coroutines. + With this release, we added + [`kotlinx-coroutines-play-services`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-play-services/){: .external} + to `firebase-inappmessaging-ktx` as a transitive dependency, which exposes + the `Task.await()` suspend function to convert a + [`Task`](https://developers.google.com/android/guides/tasks) into a Kotlin + coroutine. + +# 20.1.3 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 20.1.2 +* [changed] Updated dependencies of `play-services-basement`, + `play-services-base`, and `play-services-tasks` to their latest versions + (v18.0.0, v18.0.1, and v18.0.1, respectively). For more information, see the + [note](#basement18-0-0_base18-0-1_tasks18-0-1) at the top of this release + entry. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 20.1.1 +- [changed] Updated the gRPC dependency version. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 20.1.0 +* [changed] Migrated to Glide library for image downloading. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 20.0.0 +* [changed] Internal infrastructure improvements. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 19.1.5 +* [fixed] Fixed `WindowManager$BadTokenException` when showing an in-app + message. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 19.1.4 +* [fixed] Fixed in-app message button click not working in Android 11 + because of package visibility changes. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 19.1.3 +* [changed] Internal changes to maintain compatibility with other Firebase + SDKs. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 19.1.2 +* [changed] Internal changes to maintain compatibility with other Firebase + SDKs. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 19.1.1 +* [fixed] Improved link handling on devices without any browser installed + or without Chrome installed. + +* [feature] Added the ability to register a dismiss listener that reacts to + message dismissal. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 19.1.0 +* [changed] Updated the protocol buffer dependency to the newer + `protobuf-javalite` artifact. The new artifact is incompatible with the old + one, so this library needed to be upgraded to avoid conflicts. + No developer action is necessary. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 19.0.7 +* [fixed] Improved handling of activity transitions. + (GitHub [Issue #1410](//github.com/firebase/firebase-android-sdk/issues/1410) + and [Issue #1092](//github.com/firebase/firebase-android-sdk/issues/1092)) + +* [changed] Migrated to use the [firebase_installations] service _directly_ + instead of using an indirect dependency via the Firebase Instance ID SDK. + + {% include "docs/reference/android/client/_includes/_iid-indirect-dependency-solutions.html" %} + + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 19.0.6 +* [fixed] Fixed issue causing apps to become unresponsive in limited network + conditions. [GitHub Issue #1430](//github.com/firebase/firebase-android-sdk/issues/1430) + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 19.0.5 +* [fixed] Fixed issue where campaigns with frequency limits were not properly + displaying multiple times. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 19.0.4 +* [fixed] Fixed issue with messages not being fetched on app first open. + +* [fixed] Fixed issue with first foreground trigger not being picked up. + +* [changed] Internal migration to use the [firebase_installations] service. + + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 19.0.3 +* [changed] Internal changes to enable future SDK improvements. + + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-inappmessaging` library. The Kotlin extensions library has no +additional updates. + +# 19.0.2 +* [changed] Updated version of Dagger to 2.24. +* [changed] Made info messages more clear in logcat. + + +## Kotlin +* [feature] The beta release of a [inappmessaging] Android library + with Kotlin extensions is now available. The Kotlin extensions library + transitively includes the base `firebase-inappmessaging` + library. To learn more, visit the + [[inappmessaging] KTX documentation](/docs/reference/kotlin/com/google/firebase/inappmessaging/ktx/package-summary). + +# 19.0.1 +* [changed] Internal changes to accommodate open-sourcing of the library and + to ensure functionality alignment with other SDK releases. + +# 19.0.0 +* [changed] Versioned to add nullability annotations to improve the Kotlin + developer experience. No other changes. + +# 18.0.2 +* [fixed] Updated to send engagement metrics via [analytics]. +* [fixed] Fixed issue with callbacks triggering for Card templates. + +# 17.2.0 +* [feature] Adds support for card in-app messages. +* [feature] Adds direct triggering (via [inappmessaging] SDK) of in-app + messages. + +# 17.1.1 +* [fixed] Fixed [firestore] and [inappmessaging] compatibility on Android + API level 19 (KitKat). The underlying issue was that [firestore] and + [cloud_functions] couldn't agree on which ciphers to use; this update fixes + this issue by overriding the set of ciphers that they use. Refer to + [GitHub issue 244](https://github.com/firebase/firebase-android-sdk/issues/244) + for more information. + +# 17.1.0 +* [feature] Adds functionality to programmatically register listeners for + updates on in-app engagement (for example, impression, click, display errors). + See + [`FirebaseInAppMessaging.addClickListener()`](/docs/reference/android/com/google/firebase/inappmessaging/FirebaseInAppMessaging.addClickListener()) + for more details. + +# 17.0.5 +* [fixed] Users with restricted API keys can now use the SDK as expected. + +# 17.0.3 +* [fixed] Improved caching logic, added safeguards for cache expiration, and cleaned up API surface to prepare for open sourcing the [inappmessaging]-display SDK. + +# 17.0.1 +* [fixed] Fixed an issue where [fiam] and Firestore could not be included/built into the same app, because of an obfuscation collision. + +# 17.0.0 +* [feature] The initial public beta release of the Firebase In-App Messaging SDK for Android is now available. To learn more, see the [Firebase In-App Messaging documentation](/docs/in-app-messaging). + diff --git a/firebase-inappmessaging/firebase-inappmessaging.gradle b/firebase-inappmessaging/firebase-inappmessaging.gradle index c41ed775b54..b77b49c78f9 100644 --- a/firebase-inappmessaging/firebase-inappmessaging.gradle +++ b/firebase-inappmessaging/firebase-inappmessaging.gradle @@ -144,10 +144,12 @@ dependencies { testImplementation 'com.google.guava:guava:30.1-android' testImplementation 'androidx.test:core:1.2.0' + androidTestImplementation project(':integ-testing') + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation "androidx.annotation:annotation:1.0.0" androidTestImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation "com.google.truth:truth:$googleTruthVersion" - androidTestImplementation 'org.mockito:mockito-core:2.25.0' androidTestImplementation 'org.awaitility:awaitility:3.1.0' androidTestImplementation "io.grpc:grpc-testing:$grpcVersion" androidTestImplementation 'com.linkedin.dexmaker:dexmaker:2.28.1' diff --git a/firebase-inappmessaging/src/androidTest/java/com/google/firebase/inappmessaging/StrictModeTest.java b/firebase-inappmessaging/src/androidTest/java/com/google/firebase/inappmessaging/StrictModeTest.java new file mode 100644 index 00000000000..c48618935b7 --- /dev/null +++ b/firebase-inappmessaging/src/androidTest/java/com/google/firebase/inappmessaging/StrictModeTest.java @@ -0,0 +1,47 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.inappmessaging; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions.Builder; +import com.google.firebase.testing.integ.StrictModeRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class StrictModeTest { + + @Rule public StrictModeRule strictMode = new StrictModeRule(); + + @Test + public void initializingFirebaseInAppMessaging_shouldNotViolateStrictMode() { + strictMode.runOnMainThread( + () -> { + FirebaseApp app = + FirebaseApp.initializeApp( + ApplicationProvider.getApplicationContext(), + new Builder() + .setApiKey("api") + .setProjectId("123") + .setApplicationId("appId") + .build(), + "hello"); + app.get(FirebaseInAppMessaging.class); + }); + } +} diff --git a/firebase-inappmessaging/src/main/java/com/google/firebase/inappmessaging/FirebaseInAppMessagingRegistrar.java b/firebase-inappmessaging/src/main/java/com/google/firebase/inappmessaging/FirebaseInAppMessagingRegistrar.java index 763004d4829..2fe096f8fe6 100644 --- a/firebase-inappmessaging/src/main/java/com/google/firebase/inappmessaging/FirebaseInAppMessagingRegistrar.java +++ b/firebase-inappmessaging/src/main/java/com/google/firebase/inappmessaging/FirebaseInAppMessagingRegistrar.java @@ -52,11 +52,14 @@ */ @Keep public class FirebaseInAppMessagingRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-fiam"; + @Override @Keep public List> getComponents() { return Arrays.asList( Component.builder(FirebaseInAppMessaging.class) + .name(LIBRARY_NAME) .add(Dependency.required(Context.class)) .add(Dependency.required(FirebaseInstallationsApi.class)) .add(Dependency.required(FirebaseApp.class)) @@ -67,7 +70,7 @@ public List> getComponents() { .factory(this::providesFirebaseInAppMessaging) .eagerInDefaultApp() .build(), - LibraryVersionComponent.create("fire-fiam", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } private FirebaseInAppMessaging providesFirebaseInAppMessaging(ComponentContainer container) { diff --git a/firebase-installations/CHANGELOG.md b/firebase-installations/CHANGELOG.md index 1b8baeab0a2..40d4a4b5bea 100644 --- a/firebase-installations/CHANGELOG.md +++ b/firebase-installations/CHANGELOG.md @@ -1,4 +1,7 @@ -# v17.0.0 +# Unreleased + +# 17.1.0 +* [changed] Internal changes to ensure functionality alignment with other + SDK releases. For more details, refer to the + [Firebase Instance ID v21.1.0 release notes](/support/release-notes/android#iid_v21-1-0). -- [added] The Firebase Installations Service is an infrastructure service for Firebase services that creates unique identifiers and authentication tokens for Firebase clients (called "Firebase Installations") enabling Firebase Targeting, i.e. interoperation between Firebase services. -- [added] The Firebase Installations SDK introduces the Firebase Installations API. Developers that use API-restrictions for their API-Key may experience blocked requests (https://stackoverflow.com/questions/58495985/). This problem can be mitigated by following the instructions found [here](API_KEY_RESTRICTIONS.md). \ No newline at end of file diff --git a/firebase-installations/gradle.properties b/firebase-installations/gradle.properties index b58bf86ff76..22bb5703b26 100644 --- a/firebase-installations/gradle.properties +++ b/firebase-installations/gradle.properties @@ -1,2 +1,2 @@ -version=17.0.3 -latestReleasedVersion=17.0.2 +version=17.0.4 +latestReleasedVersion=17.0.3 diff --git a/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallationsRegistrar.java b/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallationsRegistrar.java index f50186beeea..901375a1105 100644 --- a/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallationsRegistrar.java +++ b/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallationsRegistrar.java @@ -28,11 +28,13 @@ /** @hide */ @Keep public class FirebaseInstallationsRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-installations"; @Override public List> getComponents() { return Arrays.asList( Component.builder(FirebaseInstallationsApi.class) + .name(LIBRARY_NAME) .add(Dependency.required(FirebaseApp.class)) .add(Dependency.optionalProvider(HeartBeatController.class)) .factory( @@ -41,6 +43,6 @@ public List> getComponents() { c.get(FirebaseApp.class), c.getProvider(HeartBeatController.class))) .build(), HeartBeatConsumerComponent.create(), - LibraryVersionComponent.create("fire-installations", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/firebase-messaging-directboot/CHANGELOG.md b/firebase-messaging-directboot/CHANGELOG.md new file mode 100644 index 00000000000..459f7ec15b7 --- /dev/null +++ b/firebase-messaging-directboot/CHANGELOG.md @@ -0,0 +1,110 @@ +# Unreleased + +# 23.1.0 +* [changed] Internal changes to ensure functionality alignment with other + SDK releases. + +# 23.0.8 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). +# 23.0.7 +* [changed] Updated `minSdkVersion` to 19 to match [messaging_longer] + `minSdkVersion`. + +* [changed] Updated `FirebaseMessagingDirectBootReceiver` to match + [messaging_longer] `FirebaseInstanceIdReceiver`. + +* [changed] Removed unused dependencies. + +# 23.0.6 +* [changed] Internal changes to ensure functionality alignment with other + SDK releases. For more details, refer to the + [[messaging_longer] v23.0.6 release notes](/support/release-notes/android#messaging_v23-0-6). +# 23.0.5 +* [changed] Internal changes to ensure functionality alignment with other + SDK releases. For more details, refer to the + [[messaging_longer] v23.0.5 release notes](/support/release-notes/android#messaging_v23-0-5). + +# 23.0.3 +* [changed] Internal changes to ensure functionality alignment with other + SDK releases. For more details, refer to the + [[messaging_longer] v23.0.3 release notes](/support/release-notes/android#messaging_v23-0-3). + +# 23.0.2 +* [fixed] Fixed an issue where the messaging component in + the [firebase_bom_long] leaked the `httpcomponents` transitive dependencies. + +# 23.0.1 +* [changed] Updated dependencies of `play-services-basement`, + `play-services-base`, and `play-services-tasks` to their latest versions + (v18.0.0, v18.0.1, and v18.0.1, respectively). For more information, see the + [note](#basement18-0-0_base18-0-1_tasks18-0-1) at the top of this release + entry. + +* [changed] Internal changes to ensure functionality alignment with other SDK + releases. For more details, refer to the + [[messaging_longer] v23.0.1 release note](/support/release-notes/android#messaging_v23-0-1). + +# 23.0.0 +* [changed] Internal changes to ensure functionality alignment with other + SDK releases. For more details, refer to the + [[messaging_longer] v23.0.0 release notes](/support/release-notes/android#messaging_v23-0-0). + +# 22.0.0 +* [changed] Internal changes to ensure functionality alignment with other + SDK releases. + +* [changed] Internal changes to support dynamic feature modules. + +* [changed] Internal infrastructure improvements. + +# 21.1.0 +* [changed] Internal changes to ensure functionality alignment with other + SDK releases. For more details, refer to the + [[messaging_longer] v21.1.0 release notes](/support/release-notes/android#messaging_v21-1-0). + +# 21.0.1 +* [changed] Internal changes to ensure functionality alignment with other SDK + releases. For more details, refer to the + [[messaging_longer] v21.0.1 release note](/support/release-notes/android#messaging_v21-0-1). + +# 21.0.0 +* [changed] Internal changes to ensure functionality alignment with other SDK + releases. For more details, refer to the + [[messaging_longer] v21.0.0 release note](/support/release-notes/android#messaging_v21-0-0). + +# 20.3.0 +* [changed] Internal changes to the Google Play services interface to improve + future development velocity. + +# 20.2.4 +* [changed] Internal changes to ensure functionality alignment with other SDK + releases. For more information, refer to the + [Firebase Installations v16.3.3 release notes](/support/release-notes/android#installations_v16-3-3). + +# 20.2.3 +* [changed] Internal changes to ensure functionality alignment with other SDK + releases. For more details, see the + [`firebase-messaging` v20.2.3 release note](/support/release-notes/android#messaging_v20-2-3). + +# 20.2.2 +Warning: **This version of `firebase-messaging-directboot` (v20.2.2) should not +be used.** A related library has a known issue (for more details, see +[`firebase-messaging` v20.2.2](/support/release-notes/android#messaging_v20-2-2)). +A fix for this issue was released on July 08, 2020 +(see [v20.2.3](/support/release-notes/android#messaging-directboot_v20-2-3)). + +* [changed] Internal improvements. + +# 20.2.1 +* [changed] Internal changes to ensure functionality alignment with other SDK + releases. For more information, refer to the + [Firebase Instance ID v20.2.1 release notes](/support/release-notes/android#iid_v20-2-1). + + +# 20.2.0 +* [feature] The Firebase Cloud Messaging Direct Boot SDK is now available + and supports receiving FCM messages in Direct Boot mode. See + [Receive FCM messages in direct boot mode](/docs/cloud-messaging/android/receive#receive_fcm_messages_in_direct_boot_mode) + for more information. + diff --git a/firebase-messaging/CHANGELOG.md b/firebase-messaging/CHANGELOG.md new file mode 100644 index 00000000000..a22bf487c22 --- /dev/null +++ b/firebase-messaging/CHANGELOG.md @@ -0,0 +1,396 @@ +# Unreleased + +# 23.1.0 +* [unchanged] Updated to accommodate the release of the updated + [messaging_longer] Kotlin extensions library. + + +## Kotlin +The Kotlin extensions library transitively includes the updated + `firebase-messaging` library. The Kotlin extensions library has the following + additional updates: + +* [feature] Firebase now supports Kotlin coroutines. + With this release, we added + [`kotlinx-coroutines-play-services`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-play-services/){: .external} + to `firebase-messaging-ktx` as a transitive dependency, which exposes the + `Task.await()` suspend function to convert a + [`Task`](https://developers.google.com/android/guides/tasks) into a Kotlin + coroutine. + +# 23.0.8 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-messaging` library. The Kotlin extensions library has no additional +updates. + +# 23.0.7 +* [changed] Message broadcasts now finish immediately after binding to the + service. This change should reduce the chance of ANRs. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-messaging` library. The Kotlin extensions library has no additional +updates. + +# 23.0.6 +* [changed] Added the `POST_NOTIFICATIONS` permission to enable posting + notifications when targeting SDK level 33. See [messaging] guidance + on how to [request runtime notification permission on Android 13+](/docs/cloud-messaging/android/client#request-permission13) + +* [fixed] Added an annotation to an internal class to fix a missing class + warning. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-messaging` library. The Kotlin extensions library has no additional +updates. + +# 23.0.5 +* [fixed] Fixed a dependency on the `firebase-datatransport` layer. + ([GitHub #3716](https://github.com/firebase/firebase-android-sdk/issues/3716){: .external}) + +* [fixed] Upgraded logging priority for message delivery events to avoid + dropped logs. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-messaging` library. The Kotlin extensions library has no additional +updates. + +# 23.0.3 +* [fixed] Removed test resources from library. + +* [fixed] Changed to catch `RuntimeException` when getting the `Bundle` from + an `Activity Intent` while checking for notification analytics data. + +* [changed] Internal changes to notification building methods. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-messaging` library. The Kotlin extensions library has no additional +updates. + +# 23.0.2 +* [fixed] Fixed an issue where the messaging component in + the [firebase_bom_long] leaked the `httpcomponents` transitive dependencies. + + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-messaging` library. The Kotlin extensions library has no additional +updates. + +# 23.0.1 +* [changed] Updated to the latest version of the `firebase-datatransport` + library. + +* [changed] Updated dependencies of `play-services-basement`, + `play-services-base`, and `play-services-tasks` to their latest versions + (v18.0.0, v18.0.1, and v18.0.1, respectively). For more information, see the + [note](#basement18-0-0_base18-0-1_tasks18-0-1) at the top of this release + entry. + +* [fixed] On Android 7.0 and earlier, the SDK now logs that a notification was + opened after `onActivityCreated` to avoid a race condition when unparceling + the extras Bundle. + +* [fixed] Switched to stopping an image download by canceling a `Future` to + interrupt the download thread. This change avoids errors that can occur in the + image downloading library when trying to close the stream on a different thread + than the one that started the download. + +* [fixed] Fixed reference documentation for [`RemoteMessage.getMessageId()`](/docs/reference/android/com/google/firebase/messaging/RemoteMessage#public-string-getmessageid) + and updated obsolete references to Google Cloud Messaging (GCM). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-messaging` library. The Kotlin extensions library has no additional +updates. + +# 23.0.0 +* [changed] Due to its + [dependency on Google Play services](/docs/android/android-play-services), + this SDK now requires devices and emulators to target API level 19 (KitKat) + or higher and to use Android 4.4 or higher. + +* [feature] Added methods for determining and controlling whether Google + Play services is set as the app’s notification delegate. By default, FCM + will now set Google Play services as the app’s notification delegate so + that it is allowed to display notifications for the app. This could be used + in the future to show an app’s notifications without needing to start the + app, which may improve message reliability and timeliness. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-messaging` library. The Kotlin extensions library has no additional +updates. + +# 22.0.0 +* [changed] Removed dependency on the deprecated Firebase Instance ID SDK. + + Caution: **This is a breaking change for apps that use [messaging] and the + deprecated Firebase Instance ID API to manage registration tokens.**
We + strongly recommend + [migrating to [messaging]'s token APIs](/docs/projects/manage-installations#fid-iid). + If you're unable to migrate to the replacement APIs, add a direct dependency + on the `firebase-iid` library to your `build.gradle` file. + +* [feature] Changed to open an `Activity` directly when a notification is + tapped instead of passing it through `FirebaseMessagingService`. This change + is to comply with Android 12 notification trampoline restrictions. + +* [feature] Internal changes to use proto instead of JSON for logging. + +* [changed] Internal changes to support dynamic feature modules. + +* [changed] Internal infrastructure improvements. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-messaging` library. The Kotlin extensions library has no additional +updates. + +# 21.1.0 +* [feature] Migrated internal handling of new token callbacks and + notification actions from Firebase Instance ID to [firebase_messaging]. + +* [feature] Added functionality to generate [messaging] tokens from + `FirebaseMessaging.getToken`, while continuing to call through to Firebase + Instance ID if it is present. This will allow [firebase_messaging] to + remove its dependency on Firebase Instance ID in the future. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-messaging` library. The Kotlin extensions library has no additional +updates. + +# 21.0.1 +* [changed] Updated to latest version of the `firebase-datatransport` library. + +* [feature] The SDK now gracefully handles missing default resources. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-messaging` library. The Kotlin extensions library has no additional +updates. + +# 21.0.0 +* [feature] Migrated auto-initialization from Firebase Instance ID to + [firebase_messaging]. + +* [feature] Added a check for incompatible versions of Firebase Instance ID. + An exception is thrown during instantiation if one is found. + +* [fixed] Fixed an issue where events were erronously logged to + [firebase_analytics] twice. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-messaging` library. The Kotlin extensions library has no additional +updates. + +# 20.3.0 +* [feature] Added + [`getToken`](/docs/reference/android/com/google/firebase/messaging/FirebaseMessaging.html#getToken()) + and + [`deleteToken`](/docs/reference/android/com/google/firebase/messaging/FirebaseMessaging.html#deleteToken()) + methods directly to `FirebaseMessaging`. + +* [changed] Internal changes to the Google Play services interface to improve + future development velocity. + + +## Kotlin +* [feature] The [messaging_longer] Android library with Kotlin + extensions is now available. The Kotlin extensions library transitively + includes the base `firebase-messaging` library. To learn more, visit the + [[messaging_longer] KTX documentation](/docs/reference/kotlin/com/google/firebase/messaging/ktx/package-summary). + +# 20.2.4 +* [changed] Internal changes to ensure functionality alignment with other SDK + releases. For more information, refer to the + [Firebase Installations v16.3.3 release notes](/support/release-notes/android#installations_v16-3-3). + +# 20.2.3 +* [fixed] Fixed an issue that caused an app to crash when a user tapped on a + received notification. + +# 20.2.2 +Warning: **This version of `firebase-messaging` (v20.2.2) should not be used.** +It has a known issue that causes an app to crash when a user taps on a +received notification. A fix for this issue was released on July 08, 2020 +(see [v20.2.3](/support/release-notes/android#messaging_v20-2-3)). + +* [changed] Internal improvements. + +# 20.2.1 +* [changed] Internal changes to ensure functionality alignment with other SDK + releases. For more information, refer to the + [Firebase Instance ID v20.2.1 release notes](/support/release-notes/android#iid_v20-2-1). + +# 20.2.0 +* [changed] Internal changes to ensure functionality alignment with other SDK + releases (for more information, refer to the + [[messaging_longer] Direct Boot v20.2.0 release notes](/support/release-notes/android#messaging-directboot_v20-2-0)). + +# 20.1.7 +* [changed] Internal changes to ensure functionality alignment with other SDK + releases (for more information, refer to the + [Firebase Instance ID v20.1.7 release notes](/support/release-notes/android#iid_v20-1-7)). + +# 20.1.6 +* [fixed] Fixed a bug in topic syncing that was causing increased usage of + shared system resources when waiting for a working network connection. + +# 20.1.5 +Warning: In some cases, `firebase-messaging` v20.1.4 and v20.1.5 are erroneously +consuming system resources which can negatively impact the performance of a +user's device. To avoid this effect, **update your app's version of +`firebase-messaging` to +[v20.1.6](/support/release-notes/android#messaging_v20-1-6) or later**. + +* [changed] Internal changes to ensure functionality alignment with other SDK releases. + +# 20.1.4 +Warning: In some cases, `firebase-messaging` v20.1.4 and v20.1.5 are erroneously +consuming system resources which can negatively impact the performance of a +user's device. To avoid this effect, **update your app's version of +`firebase-messaging` to +[v20.1.6](/support/release-notes/android#messaging_v20-1-6) or later**. + +* [changed] Internal changes to ensure functionality alignment with other SDK releases. + +# 20.1.3 +* [changed] Internal changes to ensure functionality alignment with other SDK + releases. + +# 20.1.2 +**As of v20.1.1, the [messaging_longer] SDK depends on the +[installations_sdk]. Learn about possible impacts in the +[v20.1.1 release notes](/support/release-notes/android#messaging_v20-1-1).** + +* [changed] Internal changes to ensure functionality alignment with other + SDK releases (for more information, refer to the bug fix in the [Firebase + Instance ID v20.1.1 release notes](/support/release-notes/android#iid_v20-1-1)). + +# 20.1.1 +Warning: This version of `firebase-messaging` (v20.1.1) has known issues +involving silent failures and should not be used. A fix for these issues was +released on [March 03, 2020](/support/release-notes/android#2020-03-03). + +* [changed] Changed the default for notification titles. Previously, an empty + title was replaced with the app's label, but now an empty title causes the + notification title to be omitted. + +* [fixed] Fixed an issue that could cause ANRs when receiving messages. + +* [changed] [messaging_longer] now transitively depends on the + [installations_sdk]. After updating to the latest dependency versions, make + sure that push notifications still work as expected. Also, be aware of the + following: + + * The [messaging] registration tokens of installed instances of your apps + might change once after updating dependencies to their latest versions. To + learn if your apps are affected, review the + [firebase_installations] documentation. Also, + make sure to + monitor + [messaging] registration token generation using the + #onNewToken implementation. + + * Apps that use the Firebase auto-initialization process and the Gradle plugin + to convert `google-services.json` into resources are unaffected. However, + apps that create their own `FirebaseOptions` instances must provide a valid + API key, Firebase project ID, and application ID. + +# 20.1.0 +* [feature] Added + [`setDeliveryMetricsExportToBigQuery(boolean)`](/docs/reference/android/com/google/firebase/messaging/FirebaseMessaging.html#setDeliveryMetricsExportToBigQuery(boolean)) + and + [`deliveryMetricsExportToBigQueryEnabled()`](/docs/reference/android/com/google/firebase/messaging/FirebaseMessaging.html#deliveryMetricsExportToBigQueryEnabled()) + to control and query if messsage delivery metrics are exported to BigQuery. + +* [changed] Changed to catch and log NullPointerException when trying to close + the image download stream. This NPE can happen if the image download takes too + long and times out. + +# 20.0.1 +* [fixed] Fixed notifications on API level 24 and later to display the event + time when `event_time` is set. + +# 20.0.0 +* [feature] Added support for more Android notification parameters, including: + `ticker`, `sticky`,`event_time`, `local_only`, `notification_priority`, + `default_sound`, `default_vibrate_timings`, `default_light_settings`, + `visibility`, `notification_count`, `vibrate_timings` and `light_settings`. + +* [feature] Added support for Android notifications that include an image. + +* [changed] Added nullability annotations to improve the Kotlin developer + experience. + +# 19.0.1 +* [fixed] Fixed an issue where `FirebaseMessagingService.onNewToken` would be + invoked for tokens created for non-default FirebaseApp instances. +* [fixed] SDK now only retries topic subscriptions and token registration on + the following errors: "ERROR_SERVICE_NOT_AVAILABLE" and + "ERROR_INTERNAL_SERVER_ERROR". + +# 18.0.0 +* [changed] Updated minSdkVersion to API level 16. + +# 17.6.0 +* [feature] Added functionality to automatically download and show an image in + a notification message. Retrieve the image URL set in the message with the + `getImageUrl` method in + [`RemoteMessage.Notification`](/docs/reference/android/com/google/firebase/messaging/RemoteMessage.Notification). + +# 17.5.0 +* [changed] Added internal improvements and refactored code. + +# 17.4.0 +* [feature] Added `getChannelId` method to [`RemoteMessage.Notification`](/docs/reference/android/com/google/firebase/messaging/RemoteMessage.Notification) for getting the channel ID set in a notification message. +* [fixed] Fixed a rare `ClassCastException` while receiving a message. + +# 17.3.4 +* [fixed] Bug fixes and internal improvements. + +# 17.3.2 +* [fixed] Fixed an issue that would occasionally cause apps to crash with + Android Not Responding (ANR) errors when receiving a message. + +# 17.3.0 +* [changed] Incremented the version number to 17.3.0 due to internal SDK + changes. These changes do not affect client functionality, and developers + do not need to take any action. + +# 17.1.0 +* [feature] Added `onNewToken` method to [`FirebaseMessagingService`](/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService) which is invoked when the app gets a new Instance ID token or its existing token changes. + +# 17.0.0 +* [feature] Added `getPriority()` and `getOriginalPriority()` methods to + [`RemoteMessage`](/docs/reference/android/com/google/firebase/messaging/RemoteMessage). + +* [changed] The methods `subscribeToTopic()` and `unsubscribeFromTopic()` on + [`FirebaseMessaging`](/docs/reference/android/com/google/firebase/messaging/FirebaseMessaging) + now return a + [`Task`](/docs/reference/android/com/google/android/gms/tasks/Task) that can + be used to see when the request has completed. + diff --git a/firebase-messaging/firebase-messaging.gradle b/firebase-messaging/firebase-messaging.gradle index e57ba862957..8058419fc09 100644 --- a/firebase-messaging/firebase-messaging.gradle +++ b/firebase-messaging/firebase-messaging.gradle @@ -133,4 +133,13 @@ dependencies { testImplementation 'androidx.test.ext:truth:1.4.0' testImplementation 'androidx.test.services:test-services:1.2.0' testImplementation 'androidx.core:core:1.6.0' + + androidTestImplementation project(':integ-testing') + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation "com.google.truth:truth:$googleTruthVersion" + androidTestImplementation 'junit:junit:4.12' + androidTestImplementation "androidx.annotation:annotation:1.0.0" + androidTestImplementation 'org.mockito:mockito-core:2.25.0' + androidTestImplementation 'org.mockito:mockito-inline:2.25.0' } diff --git a/health-metrics/macrobenchmark/template/benchmark/src/main/AndroidManifest.xml.mustache b/firebase-messaging/src/androidTest/AndroidManifest.xml similarity index 68% rename from health-metrics/macrobenchmark/template/benchmark/src/main/AndroidManifest.xml.mustache rename to firebase-messaging/src/androidTest/AndroidManifest.xml index 15cff250146..f8e83dd5006 100644 --- a/health-metrics/macrobenchmark/template/benchmark/src/main/AndroidManifest.xml.mustache +++ b/firebase-messaging/src/androidTest/AndroidManifest.xml @@ -1,5 +1,5 @@ - + @@ -14,12 +14,13 @@ + package="com.google.firebase.installations"> - - - - + + + + + diff --git a/firebase-messaging/src/androidTest/java/com/google/firebase/messaging/StrictModeTest.java b/firebase-messaging/src/androidTest/java/com/google/firebase/messaging/StrictModeTest.java new file mode 100644 index 00000000000..98972a9340e --- /dev/null +++ b/firebase-messaging/src/androidTest/java/com/google/firebase/messaging/StrictModeTest.java @@ -0,0 +1,47 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.messaging; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions.Builder; +import com.google.firebase.testing.integ.StrictModeRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class StrictModeTest { + + @Rule public StrictModeRule strictMode = new StrictModeRule(); + + @Test + public void initializingFirebaseMessaging_shouldNotViolateStrictMode() { + strictMode.runOnMainThread( + () -> { + FirebaseApp app = + FirebaseApp.initializeApp( + ApplicationProvider.getApplicationContext(), + new Builder() + .setApiKey("api") + .setProjectId("123") + .setApplicationId("appId") + .build(), + "hello"); + app.get(FirebaseMessaging.class); + }); + } +} diff --git a/firebase-messaging/src/main/java/com/google/firebase/messaging/FirebaseMessagingRegistrar.java b/firebase-messaging/src/main/java/com/google/firebase/messaging/FirebaseMessagingRegistrar.java index bf4e94fd246..f2941fd59e4 100644 --- a/firebase-messaging/src/main/java/com/google/firebase/messaging/FirebaseMessagingRegistrar.java +++ b/firebase-messaging/src/main/java/com/google/firebase/messaging/FirebaseMessagingRegistrar.java @@ -38,11 +38,14 @@ @KeepForSdk @Keep public class FirebaseMessagingRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-fcm"; + @Override @Keep public List> getComponents() { return Arrays.asList( Component.builder(FirebaseMessaging.class) + .name(LIBRARY_NAME) .add(Dependency.required(FirebaseApp.class)) .add(Dependency.optional(FirebaseInstanceIdInternal.class)) .add(Dependency.optionalProvider(UserAgentPublisher.class)) @@ -62,6 +65,6 @@ public List> getComponents() { container.get(Subscriber.class))) .alwaysEager() .build(), - LibraryVersionComponent.create("fire-fcm", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/firebase-ml-modeldownloader/CHANGELOG.md b/firebase-ml-modeldownloader/CHANGELOG.md new file mode 100644 index 00000000000..1995e3e58ff --- /dev/null +++ b/firebase-ml-modeldownloader/CHANGELOG.md @@ -0,0 +1,105 @@ +# Unreleased + +# 24.1.0 +* [unchanged] Updated to accommodate the release of the updated + [firebase_ml] Kotlin extensions library. + + +## Kotlin +The Kotlin extensions library transitively includes the updated + `firebase-ml-modeldownloader` library. The Kotlin extensions library has the + following additional updates: + +* [feature] Firebase now supports Kotlin coroutines. + With this release, we added + [`kotlinx-coroutines-play-services`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-play-services/){: .external} + to `firebase-ml-modeldownloader-ktx` as a transitive dependency, which + exposes the `Task.await()` suspend function to convert a + [`Task`](https://developers.google.com/android/guides/tasks) into a Kotlin + coroutine. + +# 24.0.5 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-ml-modeldownloader` library. The Kotlin extensions library has no +additional updates. +# 24.0.4 +* [fixed] Fixed a race condition that was caused when differently sized + models were concurrently downloaded using this SDK and the Model Downloader from + the `com.google.firebase:firebase-ml-common` SDK. + (#3321) + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-ml-modeldownloader` library. The Kotlin extensions library has no +additional updates. +# 24.0.3 +* [changed] Updated dependencies of `play-services-basement`, + `play-services-base`, and `play-services-tasks` to their latest versions + (v18.0.0, v18.0.1, and v18.0.1, respectively). For more information, see the + [note](#basement18-0-0_base18-0-1_tasks18-0-1) at the top of this release + entry. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-ml-modeldownloader` library. The Kotlin extensions library has no +additional updates. +# 24.0.2 +* [fixed] Fixed an issue where `FirebaseModelDownloader.getInstance` would + crash when using non-default FirebaseApp instances. + (#3321) +* [changed] Updated to the latest version of the `firebase-datatransport` + library. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-ml-modeldownloader` library. The Kotlin extensions library has no +additional updates. +# 24.0.1 +* [fixed] Added support for Android API key restrictions. + +# 24.0.0 +- [changed] Internal infrastructure improvements. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-ml-modeldownloader` library. The Kotlin extensions library has no +additional updates. + +# 23.0.1 +* [unchanged] Updated to accommodate the release of the [firebase_ml] + Kotlin extensions library. + + +## Kotlin +* [feature] The beta release of a [firebase_ml] Android library with + Kotlin extensions is now available. The Kotlin extensions library transitively + includes the base `firebase-ml-model-downloader` library. To learn more, + visit the + [[firebase_ml] KTX documentation](/docs/reference/android/com/google/firebase/ml/modeldownloader/package-summary). + +# 23.0.0 +This release includes the initial beta release of the +[firebase_ml] Model Downloader SDK. + +The [firebase_ml] Model Downloader SDK provides APIs for downloading models +hosted with [[firebase_ml] Custom Model Hosting](/docs/ml/use-custom-models). +This SDK is a lightweight version of the ML Kit Custom Models library +(`firebase-ml-model-interpreter`), allowing you to work with custom hosted +models without the interpreter API, which is now provided directly by TFLite +runtime. + +* [feature] Added custom hosted model download and on-device management + capabilities. + +* [feature] Added ability to get the model download ID, which allows progress + tracking of file downloads. + diff --git a/firebase-ml-modeldownloader/src/main/java/com/google/firebase/ml/modeldownloader/FirebaseModelDownloaderRegistrar.java b/firebase-ml-modeldownloader/src/main/java/com/google/firebase/ml/modeldownloader/FirebaseModelDownloaderRegistrar.java index b9b133505ab..cb92e0950ac 100644 --- a/firebase-ml-modeldownloader/src/main/java/com/google/firebase/ml/modeldownloader/FirebaseModelDownloaderRegistrar.java +++ b/firebase-ml-modeldownloader/src/main/java/com/google/firebase/ml/modeldownloader/FirebaseModelDownloaderRegistrar.java @@ -39,6 +39,7 @@ * @hide */ public class FirebaseModelDownloaderRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "firebase-ml-modeldownloader"; @Override @NonNull @@ -46,6 +47,7 @@ public class FirebaseModelDownloaderRegistrar implements ComponentRegistrar { public List> getComponents() { return Arrays.asList( Component.builder(FirebaseModelDownloader.class) + .name(LIBRARY_NAME) .add(Dependency.required(FirebaseApp.class)) .add(Dependency.required(FirebaseInstallationsApi.class)) .factory( @@ -84,6 +86,6 @@ public List> getComponents() { new CustomModelDownloadService( c.get(FirebaseApp.class), c.get(FirebaseInstallationsApi.class))) .build(), - LibraryVersionComponent.create("firebase-ml-modeldownloader", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/firebase-perf/CHANGELOG.md b/firebase-perf/CHANGELOG.md index 5caad2433c3..97f9f0b2b17 100644 --- a/firebase-perf/CHANGELOG.md +++ b/firebase-perf/CHANGELOG.md @@ -1,199 +1,242 @@ -# Firebase Performance Monitoring SDK (aka `firebase-perf` and `firebase-perf-ktx`) +# Unreleased -Refer [GMaven](https://maven.google.com/web/index.html?q=firebase-perf#com.google.firebase:firebase-perf) for the release artifacts and [Firebase Android Release Notes](https://firebase.google.com/support/release-notes/android) for the release info. +# 20.2.0 +* [unchanged] Updated to accommodate the release of the updated + [perfmon] Kotlin extensions library. -## Example Changelog -``` -## vX.Y.Z (MXX) +## Kotlin +The Kotlin extensions library transitively includes the updated + `firebase-performance` library. The Kotlin extensions library has the following + additional updates: -#### Android library / Kotlin extensions +* [feature] Firebase now supports Kotlin coroutines. + With this release, we added + [`kotlinx-coroutines-play-services`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-play-services/){: .external} + to `firebase-performance-ktx` as a transitive dependency, which exposes the + `Task.await()` suspend function to convert a + [`Task`](https://developers.google.com/android/guides/tasks) into a Kotlin + coroutine. -* {{feature}} You can now do this cool new thing. For more details, refer to the [documentation](docs/path). +# 20.1.1 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). -* {{fixed}} Fixed the `methodFoo` warning. -* {{changed}} You need to do _this_ instead of _that_. +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-performance` library. The Kotlin extensions library has no additional +updates. -``` +# 20.1.0 +* [feature] Added support for out-of-the-box measurement of screen performance + metrics for [Fragments](//developer.android.com/guide/fragments){: .external}. + For more details, visit + [Learn about screen rendering performance data](/docs/perf-mon/screen-traces?platform=android). -> **Note:** Refer go/firebase-android-release for `MXX` info. +* [fixed] Fixed a bug where screen traces were not capturing frame metrics for + multi-Activity apps. -## Unreleased +* [fixed] Excluded custom attributes that have key/value lengths of 0. -* {{fixed}} Fixed a bug where screen traces were not capturing frame metrics for multi-activity apps. -* {{feature}} Added support for measuring screen performance metrics for "Activity Fragments" out-of-the-box. -* {{fixed}} Excluded custom attributes whose key/value length is 0. -## Released +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-performance` library. The Kotlin extensions library has no additional +updates. -## v20.0.6 (M112) +# 20.0.6 +* [fixed] Fixed a null pointer exception (NPE) when instrumenting network + requests. + (#3406) -#### Android library +* [fixed] Fixed a bug where incorrect session IDs were associated with some + foreground and background traces. -* {{fixed}} Fixed a null pointer exception (NPE) when instrumenting network requests. ([GitHub Issue #3406](//github.com/firebase/firebase-android-sdk/issues/3406)) -* {{fixed}} Fixed a bug where incorrect session IDs were associated with some foreground and background traces. +* [changed] Updated dependencies of `play-services-basement`, + `play-services-base`, and `play-services-tasks` to their latest versions + (v18.0.0, v18.0.1, and v18.0.1, respectively). For more information, see the + [note](#basement18-0-0_base18-0-1_tasks18-0-1) at the top of this release + entry. -#### Kotlin extensions +## Kotlin The Kotlin extensions library transitively includes the updated `firebase-performance` library. The Kotlin extensions library has no additional updates. -## v20.0.5 (M111) - -#### Android library +# 20.0.5 +* [feature] Enabled global custom attributes for network request traces. +* [fixed] Updated log statement to differentiate an event being dropped due to + rate limiting and sampling. -* {{feature}} Enable global custom attributes on Network Requests -* {{fixed}} Update log statement to differentiate event drop because of rate limiting and sampling. - -#### Kotlin extensions +## Kotlin The Kotlin extensions library transitively includes the updated `firebase-performance` library. The Kotlin extensions library has no additional updates. -## v20.0.1 (M97) +# 20.0.4 +* [changed] Improved [perfmon] start up time by 25%. This improvement was + achieved by moving some component initialization to background threads. -#### Android library -* {{feature}} Firebase Performance logs now contain URLs to see the performance - data on the Firebase console. -* {{fixed}} Fixed RateLimiter replenishment logic and unit alignment. +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-performance` library. The Kotlin extensions library has no additional +updates. + +# 20.0.3 +* [changed] [perfmon] now has a random delay of 5 to 30 seconds before + fetching [remote_config] upon app startup. +* [fixed] Added a validation to stop screen traces with 0 total frames from + being sent to the backend. -#### Kotlin extensions +## Kotlin The Kotlin extensions library transitively includes the updated `firebase-performance` library. The Kotlin extensions library has no additional updates. -## v20.0.0 (M95) +# 20.0.2 +* [fixed] Fixed inaccurate calculation of screen activity metrics for + multi-activity apps. + (#2672) -#### Android library + Note: You may see some changes in data for frozen frames and slow rendering + metrics. -* {{feature}} Introduce Dagger as a dependency injection framework for some - parts of the code. -* {{changed}} Improved the code organization of the SDK (package restructure, - code conventions, remove unncessary annotations). -* {{changed}} Improve the launch time of the SDK. +* [fixed] Fixed issue where screen traces were not being tracked for Android + API levels 23 and below. -#### Kotlin extensions +## Kotlin The Kotlin extensions library transitively includes the updated `firebase-performance` library. The Kotlin extensions library has no additional updates. -## v19.1.1 (M89) +# 20.0.1 +* [feature] Logs for [firebase_perfmon] now contain URLs to view + performance data in the [name_appmanager]. +* [fixed] Fixed `RateLimiter` replenishment logic and unit alignment. -#### Android library -* {{feature}} The Firebase Performance Monitoring SDK is now open sourced. -* {{changed}} Improved performance event dispatch wait time from 2 hours to - 30 seconds. +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-performance` library. The Kotlin extensions library has no additional +updates. + +# 20.0.0 +* [feature] Introduce Dagger as a dependency injection framework for some + parts of the code. +* [changed] Improved the code organization of the SDK (package restructure, + code conventions, remove unncessary annotations). +* [changed] Improve the launch time of the SDK. -#### Kotlin extensions +## Kotlin The Kotlin extensions library transitively includes the updated `firebase-performance` library. The Kotlin extensions library has no additional updates. -## v19.1.0 (M87) +# 19.1.1 +* [feature] The [firebase_perfmon] SDK is now + [open sourced](//github.com/firebase/firebase-android-sdk/tree/master/firebase-perf){: .external}. +* [fixed] Fixed issue on the console logger to avoid throwing + `UnknownFormatConversionException`. -#### Android library -* {{changed}} Removed GMS dependency from {{perfmon}}. Google Play services - installation is no longer required to use firebase performance. +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-performance` library. The Kotlin extensions library has no additional +updates. + +# 19.1.0 +* [changed] Removed GMS dependency from [perfmon]. Google Play services + installation is no longer required to use [perfmon]. -* {{changed}} Improved performance event dispatch wait time from 2 hours to +* [changed] Improved performance event dispatch wait time from 2 hours to 30 seconds. -#### Kotlin extensions +## Kotlin The Kotlin extensions library transitively includes the updated `firebase-performance` library. The Kotlin extensions library has no additional updates. -## v19.0.11 (M85) - -#### Android library +# 19.0.11 +* [fixed] Upgraded protobuf dependency to the latest released version + (#2158) -* {{fixed}} Upgraded protobuf dependency to the latest released version - ([GitHub Issue #2158](//github.com/firebase/firebase-android-sdk/issues/2158)) - -#### Kotlin extensions +## Kotlin The Kotlin extensions library transitively includes the updated `firebase-performance` library. The Kotlin extensions library has no additional updates. -## v19.0.10 (M83) - -#### Android library -Note: We recommend using {{perfmon}} Gradle plugin version v1.3.4 or above with -this version of SDK. +# 19.0.10 +Note: We recommend using [perfmon] Gradle plugin v1.3.4+ with this version of +the [perfmon] SDK and above. -* {{changed}} Integrated with the `firebase-datatransport` library for +* [changed] Integrated with the `firebase-datatransport` library for performance log dispatch mechanism. -* {{fixed}} Synchronized the access to fix a race condition that was causing a +* [fixed] Synchronized the access to fix a race condition that was causing a `NullPointerException` when making network requests. - ([GitHub Issue #2096](//github.com/firebase/firebase-android-sdk/issues/2096)) + (#2096) -#### Kotlin extensions +## Kotlin The Kotlin extensions library transitively includes the updated `firebase-performance` library. The Kotlin extensions library has no additional updates. -## v19.0.9 (M80) +# 19.0.9 +* [fixed] Created lazy dependency on [firebase_remote_config] to avoid + main thread contention issue. + (#1810) -#### Android library +* [changed] Updated the protocol buffer dependency to the + `protobuf-javalite` artifact to allow for backward compatibility. -* {{fixed}} Created lazy dependency on {{firebase_remote_config}} to avoid - main thread contention issue. ([GitHub Issue #1810](//github.com/firebase/firebase-android-sdk/issues/1810)) +* [changed] Removed Guava dependency from the SDK to avoid symbol collision + with any other SDKs. -* {{changed}} Updated the protocol buffer dependency to the - `protobuf-javalite` artifact to allow for backward compatibility. +* [changed] Removed proguarding for SDK; logcat messages will show original + class paths for debugging. -* {{changed}} Removed Guava dependency from the SDK to avoid symbol collision with any other SDKs. +* [changed] Improved build configurations and dependencies to reduce SDK + size. -* {{changed}} Removed proguarding for SDK; logcat messages will show original class paths for debugging. -* {{changed}} Improved build configurations and dependencies to reduce SDK size. - -#### Kotlin extensions - -* {{feature}} The {{firebase_perfmon}} Android library with Kotlin +## Kotlin +* [feature] The [firebase_perfmon] Android library with Kotlin extensions is now available. The Kotlin extensions library transitively includes the base `firebase-performance` library. To learn more, visit the - [{{perfmon}} KTX documentation](/docs/reference/kotlin/com/google/firebase/perf/ktx/package-summary). - -## v19.0.8 (M75) + [[perfmon] KTX documentation](/docs/reference/kotlin/com/google/firebase/perf/ktx/package-summary). -#### Android library - -* {{changed}} Updated the +# 19.0.8 +* [changed] Updated the [logging message](/docs/perf-mon/get-started-android#view-log-messages) for performance events. -* {{fixed}} Silenced {{firebase_remote_config}} logging triggered by - {{firebase_perfmon}}. - ([GitHub Issue #403](//github.com/firebase/firebase-android-sdk/issues/403)) +* [fixed] Silenced [firebase_remote_config] logging triggered by + [firebase_perfmon]. + (#403) -* {{fixed}} Removed unnecessary logging. {{perfmon}} now only logs debug +* [fixed] Removed unnecessary logging. [perfmon] now only logs debug information if the `firebase_performance_logcat_enabled` setting is `true` in `AndroidManifest.xml`. Visit the documentation for details about explicitly [enabling debug logging](/docs/perf-mon/get-started-android#view-log-messages). -* {{changed}} Migrated to use the {{firebase_installations}} service _directly_ +* [changed] Migrated to use the [firebase_installations] service _directly_ instead of using an indirect dependency via the Firebase Instance ID SDK. -## v19.0.7 (M69) - -#### Android library + {% include "docs/reference/android/client/_includes/_iid-indirect-dependency-solutions.html" %} -* {{changed}} Updated dependency on the Firebase Instance ID library to v20.1.5, - which is a step towards a direct dependency on the {{firebase_installations}} +# 19.0.7 +* [changed] Updated dependency on the Firebase Instance ID library to v20.1.5, + which is a step towards a direct dependency on the [firebase_installations] service in a future release. This update to `firebase-iid` v20.1.5 fixed the following GitHub issues: @@ -201,139 +244,69 @@ updates. [#1397](//github.com/firebase/firebase-android-sdk/issues/1397), and [#1339](//github.com/firebase/firebase-android-sdk/issues/1339). -## v19.0.6 (M68) - -#### Android library - -* {{fixed}} Fixed an NPE crash when calling `trace.stop()`. - ([GitHub Issue #1383](//github.com/firebase/firebase-android-sdk/issues/1383)) - -## v19.0.5 (M62) - -#### Android library +# 19.0.6 +* [fixed] Fixed an NPE crash when calling `trace.stop()`. + (#1383) -* {{fixed}} Muted logcat logging for {{firebase_perfmon}} when +# 19.0.5 +* [fixed] Muted logcat logging for [firebase_perfmon] when `firebase_performance_logcat_enabled` is not set or set to false. ([#403](//github.com/firebase/firebase-android-sdk/issues/403)) -* {{fixed}} Skipped automatic performance event creation when +* [fixed] Skipped automatic performance event creation when `firebase_performance_collection_enabled` is set to false. -* {{changed}} Internal infrastructure improvements. +* [changed] Internal infrastructure improvements. -## v19.0.4 (M61) +# 19.0.4 +* [changed] Improved internal infrastructure to work better with + [firebase_remote_config]. -#### Android library +# 19.0.3 +* [changed] Internal infrastructure improvements. -* {{changed}} Improved internal infrastructure to work better with - {{firebase_remote_config}}. +# 19.0.2 +* [changed] Internal infrastructure improvements. ----- +# 19.0.1 +* [changed] Internal infrastructure improvements. -**NOTE:** For some historical reasons below internal versions may or may not correlate to an externally released version. However, this document keeps track of what internal version was released as an external version so that its easier to figure out what version of the SDK we were dealing with (and whether it was publicly released). Unfortunately, we did not keep records of what internal version correlated to an external version until `v16.2.0`, and so the values before that were procured as a result of manually going through history and correlating release dates. - -## 19.0.3 (M60.1): 1.0.0.282466371 - -#### Android library - -* {{changed}} Internal infrastructure improvements. - -## 19.0.2 (M59): 1.0.0.277188197 - -#### Android library - -* {{changed}} Internal infrastructure improvements. - -## 19.0.1 (M57): 1.0.0.272275548 - -#### Android library - -* {{changed}} Internal infrastructure improvements. - -## 19.0.0 (M53): - -#### Android library - -* {{changed}} Versioned to add nullability annotations to improve the Kotlin +# 19.0.0 +* [changed] Versioned to add nullability annotations to improve the Kotlin developer experience. No other changes. -## 18.0.1 (M50): 1.0.0.252929170 - -#### Android library - -* {{fixed}} Fixed an `IllegalStateException` that was thrown when an activity +# 18.0.1 +* [fixed] Fixed an `IllegalStateException` that was thrown when an activity with hardware acceleration disabled was stopped. - -## 18.0.0 (Android X - Clone of 17.0.2): 1.0.0.249530108 - -## 17.0.2 (M48): 1.0.0.249530108 - -#### Android library - -* {{fixed}} Fixed a `Null Pointer Exception` that was being observed on certain Android 7.0 devices. - -* {{fixed}} Updates to make {{perfmon}} work better with the latest version of - {{firebase_remote_config}}. - -## 17.0.1 (Unreleased): 1.0.0.242580265 - -## 17.0.0 (M47): 1.0.0.242580265 -#### Android library +# 17.0.2 +* [fixed] Fixed a `Null Pointer Exception` that was being observed on certain Android 7.0 devices. +* [fixed] Updates to make [perfmon] work better with the latest version of + [firebase_remote_config]. -* {{removed}} Removed the deprecated counter API. Use metrics API going forward. +# 17.0.0 +* [removed] Removed the deprecated counter API. Use metrics API going forward. -## 16.2.5 (M46): 1.0.0.240228580 - -#### Android library - -* {{fixed}} Fixed a bug that was causing apps using multiple processses to +# 16.2.5 +* [fixed] Fixed a bug that was causing apps using multiple processses to throw an `IllegalStateException` in the non-main processes. -## 16.2.4 (M44): 1.0.0.233854359 - -#### Android library - -* {{fixed}} Fixed a bug that was causing a `NoClassDefFoundError` to be thrown +# 16.2.4 +* [fixed] Fixed a bug that was causing a `NoClassDefFoundError` to be thrown which resulted in intermittent app crashes. +* [fixed] Updates to make [perfmon] work better with the latest version of + [firebase_remote_config]. +* [changed] [firebase_perfmon] no longer depends on [firebase_analytics]. -* {{fixed}} Updates to make {{perfmon}} work better with the latest version of - {{firebase_remote_config}}. - -* {{changed}} {{firebase_perfmon}} no longer depends on {{firebase_analytics}}. - -## 16.2.3 (M40): 1.0.0.225053256 - -#### Android library - -* {{fixed}} Bug fixes. - -## 16.2.2 (M38.1): 1.0.0.221486272 - -## 16.2.1 (M38): 1.0.0.221486272 - -#### Android library - -* {{fixed}} SDK size is now smaller. - -## 16.2.0 (M36): 1.0.0.217212991 - -#### Android library - -* {{feature}} Introduces the Sessions feature, which gives developers access to actionable insights about data captured using {{perfmon}}. - -* {{fixed}} Minor bug fixes and improvements. - -## 16.1.1 (EAP): 1.0.0.212694509 - -## 16.1.0 (M30): 1.0.0.206222422 - -#### Android library +# 16.2.3 +* [fixed] Bug fixes. -* {{fixed}} Fixed a `SecurityException` crash on certain devices that do not have Google Play Services on them. +# 16.2.1 +* [fixed] SDK size is now smaller. -## 16.0.0: 1.0.0.196558987 +# 16.2.0 +* [feature] Introduces the Sessions feature, which gives developers access to actionable insights about data captured using [perfmon]. -## 15.2.0: 1.0.0.194951622 +* [fixed] Minor bug fixes and improvements. -## 15.1.0: 1.0.0.194607773 +# 16.1.0 +* [fixed] Fixed a `SecurityException` crash on certain devices that do not have Google Play Services on them. -## 15.0.0: 1.0.0.184862077 diff --git a/firebase-perf/dev-app/src/main/AndroidManifest.xml b/firebase-perf/dev-app/src/main/AndroidManifest.xml index 643b50fb03e..c225f4fb472 100644 --- a/firebase-perf/dev-app/src/main/AndroidManifest.xml +++ b/firebase-perf/dev-app/src/main/AndroidManifest.xml @@ -38,6 +38,9 @@ + > getComponents() { return Arrays.asList( Component.builder(FirebasePerformance.class) + .name(LIBRARY_NAME) .add(Dependency.required(FirebaseApp.class)) .add(Dependency.requiredProvider(RemoteConfigComponent.class)) .add(Dependency.required(FirebaseInstallationsApi.class)) @@ -59,7 +61,7 @@ public List> getComponents() { * not to force initialize them at app startup (refer * https://github.com/google/guice/wiki/InjectingProviders#providers-for-lazy-loading)* */ - LibraryVersionComponent.create("fire-perf", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } private static FirebasePerformance providesFirebasePerformance(ComponentContainer container) { diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/config/ConfigResolver.java b/firebase-perf/src/main/java/com/google/firebase/perf/config/ConfigResolver.java index 44e5d35fe07..65e527e373c 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/config/ConfigResolver.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/config/ConfigResolver.java @@ -23,6 +23,7 @@ import com.google.firebase.perf.BuildConfig; import com.google.firebase.perf.config.ConfigurationConstants.CollectionDeactivated; import com.google.firebase.perf.config.ConfigurationConstants.CollectionEnabled; +import com.google.firebase.perf.config.ConfigurationConstants.ExperimentTTID; import com.google.firebase.perf.config.ConfigurationConstants.FragmentSamplingRate; import com.google.firebase.perf.config.ConfigurationConstants.LogSourceName; import com.google.firebase.perf.config.ConfigurationConstants.NetworkEventCountBackground; @@ -767,6 +768,38 @@ public float getFragmentSamplingRate() { return config.getDefault(); } + /** Returns if _experiment_app_start_ttid should be captured. */ + public boolean getIsExperimentTTIDEnabled() { + // Order of precedence is: + // 1. If the value exists in Android Manifest, return this value. + // 2. If the value exists through Firebase Remote Config, cache and return this value. + // 3. If the value exists in device cache, return this value. + // 4. Otherwise, return default value. + ExperimentTTID config = ExperimentTTID.getInstance(); + + // 1. Reads value in Android Manifest (it is set by developers during build time). + Optional metadataValue = getMetadataBoolean(config); + if (metadataValue.isAvailable()) { + return metadataValue.get(); + } + + // 2. Reads value from Firebase Remote Config, saves this value in cache layer if valid. + Optional rcValue = getRemoteConfigBoolean(config); + if (rcValue.isAvailable()) { + deviceCacheManager.setValue(config.getDeviceCacheFlag(), rcValue.get()); + return rcValue.get(); + } + + // 3. Reads value from cache layer. + Optional deviceCacheValue = getDeviceCacheBoolean(config); + if (deviceCacheValue.isAvailable()) { + return deviceCacheValue.get(); + } + + // 4. Returns default value if there is no valid value from above approaches. + return config.getDefault(); + } + // endregion // Helper functions for interaction with Metadata layer. diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/config/ConfigurationConstants.java b/firebase-perf/src/main/java/com/google/firebase/perf/config/ConfigurationConstants.java index f14ba7c71a0..145935db505 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/config/ConfigurationConstants.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/config/ConfigurationConstants.java @@ -661,4 +661,39 @@ protected String getMetadataFlag() { return "fragment_sampling_percentage"; } } + + protected static final class ExperimentTTID extends ConfigurationFlag { + private static ExperimentTTID instance; + + private ExperimentTTID() { + super(); + } + + protected static synchronized ExperimentTTID getInstance() { + if (instance == null) { + instance = new ExperimentTTID(); + } + return instance; + } + + @Override + protected Boolean getDefault() { + return false; + } + + @Override + protected String getRemoteConfigFlag() { + return "fpr_experiment_app_start_ttid"; + } + + @Override + protected String getDeviceCacheFlag() { + return "com.google.firebase.perf.ExperimentTTID"; + } + + @Override + protected String getMetadataFlag() { + return "experiment_app_start_ttid"; + } + } } diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/config/RemoteConfigManager.java b/firebase-perf/src/main/java/com/google/firebase/perf/config/RemoteConfigManager.java index 0986e123c16..7c27b59c3d9 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/config/RemoteConfigManager.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/config/RemoteConfigManager.java @@ -14,6 +14,8 @@ package com.google.firebase.perf.config; +import static com.google.firebase.perf.config.ConfigurationConstants.ExperimentTTID; + import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; @@ -53,6 +55,7 @@ public class RemoteConfigManager { private static final long MIN_APP_START_CONFIG_FETCH_DELAY_MS = 5000; private static final int RANDOM_APP_START_CONFIG_FETCH_DELAY_MS = 25000; + private final DeviceCacheManager cache; private final ConcurrentHashMap allRcConfigMap; private final Executor executor; private final long appStartTimeInMs; @@ -65,29 +68,25 @@ public class RemoteConfigManager { private RemoteConfigManager() { this( + DeviceCacheManager.getInstance(), new ThreadPoolExecutor( /* corePoolSize= */ 0, /* maximumPoolSize= */ 1, /* keepAliveTime= */ 0L, TimeUnit.SECONDS, new LinkedBlockingQueue()), - /* firebaseRemoteConfig= */ null // set once FirebaseRemoteConfig is initialized - ); - } - - RemoteConfigManager(Executor executor, FirebaseRemoteConfig firebaseRemoteConfig) { - this( - executor, - firebaseRemoteConfig, + /* firebaseRemoteConfig= */ null, // set once FirebaseRemoteConfig is initialized MIN_APP_START_CONFIG_FETCH_DELAY_MS + new Random().nextInt(RANDOM_APP_START_CONFIG_FETCH_DELAY_MS)); } @VisibleForTesting RemoteConfigManager( + DeviceCacheManager cache, Executor executor, FirebaseRemoteConfig firebaseRemoteConfig, long appStartConfigFetchDelayInMs) { + this.cache = cache; this.executor = executor; this.firebaseRemoteConfig = firebaseRemoteConfig; this.allRcConfigMap = @@ -315,7 +314,7 @@ private void triggerRemoteConfigFetchIfNecessary() { return; } if (allRcConfigMap.isEmpty()) { // Initial fetch. - syncConfigValues(firebaseRemoteConfig.getAll()); + allRcConfigMap.putAll(firebaseRemoteConfig.getAll()); } if (shouldFetchAndActivateRemoteConfigValues()) { triggerFirebaseRemoteConfigFetchAndActivateOnSuccessfulFetch(); @@ -342,6 +341,21 @@ protected void syncConfigValues(Map newlyFetc allRcConfigMap.remove(existingKey); } } + + // TODO: remove after experiment is over and experiment RC flag is no longer needed + // Save ExperimentTTID flag to device cache upon successful RC fetchAndActivate, because reading + // is done quite early and it is possible that RC isn't initialized yet. + ExperimentTTID flag = ExperimentTTID.getInstance(); + FirebaseRemoteConfigValue rcValue = allRcConfigMap.get(flag.getRemoteConfigFlag()); + if (rcValue != null) { + try { + cache.setValue(flag.getDeviceCacheFlag(), rcValue.asBoolean()); + } catch (Exception exception) { + logger.debug("ExperimentTTID remote config flag has invalid value, expected boolean."); + } + } else { + logger.debug("ExperimentTTID remote config flag does not exist."); + } } @VisibleForTesting diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java b/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java index 3aa363e1338..2e1bb5cd8d3 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java @@ -18,11 +18,15 @@ import android.app.Application; import android.app.Application.ActivityLifecycleCallbacks; import android.content.Context; +import android.os.Build; import android.os.Bundle; +import android.os.Process; +import android.view.View; import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.android.gms.common.util.VisibleForTesting; +import com.google.firebase.perf.config.ConfigResolver; import com.google.firebase.perf.logging.AndroidLogger; import com.google.firebase.perf.provider.FirebasePerfProvider; import com.google.firebase.perf.session.PerfSession; @@ -30,6 +34,7 @@ import com.google.firebase.perf.transport.TransportManager; import com.google.firebase.perf.util.Clock; import com.google.firebase.perf.util.Constants; +import com.google.firebase.perf.util.FirstDrawDoneListener; import com.google.firebase.perf.util.Timer; import com.google.firebase.perf.v1.ApplicationProcessState; import com.google.firebase.perf.v1.TraceMetric; @@ -69,6 +74,7 @@ public class AppStartTrace implements ActivityLifecycleCallbacks { private boolean isRegisteredForLifecycleCallbacks = false; private final TransportManager transportManager; private final Clock clock; + private final ConfigResolver configResolver; private Context appContext; /** * The first time onCreate() of any activity is called, the activity is saved as launchActivity. @@ -89,6 +95,7 @@ public class AppStartTrace implements ActivityLifecycleCallbacks { private Timer onCreateTime = null; private Timer onStartTime = null; private Timer onResumeTime = null; + private Timer firstDrawDone = null; private PerfSession startSession; private boolean isStartedFromBackground = false; @@ -134,12 +141,13 @@ static AppStartTrace getInstance(TransportManager transportManager, Clock clock) new AppStartTrace( transportManager, clock, + ConfigResolver.getInstance(), new ThreadPoolExecutor( CORE_POOL_SIZE, MAX_POOL_SIZE, /* keepAliveTime= */ MAX_LATENCY_BEFORE_UI_INIT + 10, TimeUnit.SECONDS, - new LinkedBlockingQueue<>(1))); + new LinkedBlockingQueue<>())); } } } @@ -149,9 +157,11 @@ static AppStartTrace getInstance(TransportManager transportManager, Clock clock) AppStartTrace( @NonNull TransportManager transportManager, @NonNull Clock clock, + @NonNull ConfigResolver configResolver, @NonNull ExecutorService executorService) { this.transportManager = transportManager; this.clock = clock; + this.configResolver = configResolver; this.executorService = executorService; } @@ -178,6 +188,33 @@ public synchronized void unregisterActivityLifecycleCallbacks() { isRegisteredForLifecycleCallbacks = false; } + /** + * Gets the timetamp that marks the beginning of app start, currently defined as the beginning of + * BIND_APPLICATION. Fallback to class-load time of {@link FirebasePerfProvider} when API < 24. + * + * @return {@link Timer} at the beginning of app start by Fireperf definition. + */ + private static Timer getStartTimer() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + return Timer.ofElapsedRealtime(Process.getStartElapsedRealtime()); + } + return FirebasePerfProvider.getAppStartTime(); + } + + private void recordFirstDrawDone() { + if (firstDrawDone != null) { + return; + } + this.firstDrawDone = clock.getTime(); + executorService.execute( + () -> this.logColdStart(getStartTimer(), this.firstDrawDone, this.startSession)); + + if (isRegisteredForLifecycleCallbacks) { + // After AppStart trace is queued to be logged, we can unregister this callback. + unregisterActivityLifecycleCallbacks(); + } + } + @Override public synchronized void onActivityCreated(Activity activity, Bundle savedInstanceState) { if (isStartedFromBackground || onCreateTime != null // An activity already called onCreate() @@ -206,9 +243,18 @@ public synchronized void onActivityStarted(Activity activity) { @Override public synchronized void onActivityResumed(Activity activity) { - if (isStartedFromBackground - || onResumeTime != null // An activity already called onResume() - || isTooLateToInitUI) { + if (isStartedFromBackground || isTooLateToInitUI) { + return; + } + + // Shadow-launch experiment of new app start time + final boolean isExperimentTTIDEnabled = configResolver.getIsExperimentTTIDEnabled(); + if (isExperimentTTIDEnabled) { + View rootView = activity.findViewById(android.R.id.content); + FirstDrawDoneListener.registerForNextDraw(rootView, this::recordFirstDrawDone); + } + + if (onResumeTime != null) { // An activity already called onResume() return; } @@ -228,12 +274,30 @@ public synchronized void onActivityResumed(Activity activity) { // Log the app start trace in a non-main thread. executorService.execute(this::logAppStartTrace); - if (isRegisteredForLifecycleCallbacks) { + if (!isExperimentTTIDEnabled && isRegisteredForLifecycleCallbacks) { // After AppStart trace is logged, we can unregister this callback. unregisterActivityLifecycleCallbacks(); } } + private void logColdStart(Timer start, Timer end, PerfSession session) { + TraceMetric.Builder metric = + TraceMetric.newBuilder() + .setName("_experiment_app_start_ttid") + .setClientStartTimeUs(start.getMicros()) + .setDurationUs(start.getDurationMicros(end)); + + TraceMetric.Builder subtrace = + TraceMetric.newBuilder() + .setName("_experiment_classLoadTime") + .setClientStartTimeUs(FirebasePerfProvider.getAppStartTime().getMicros()) + .setDurationUs(FirebasePerfProvider.getAppStartTime().getDurationMicros(end)); + + metric.addSubtraces(subtrace).addPerfSessions(this.startSession.build()); + + transportManager.log(metric.build(), ApplicationProcessState.FOREGROUND_BACKGROUND); + } + private void logAppStartTrace() { TraceMetric.Builder metric = TraceMetric.newBuilder() diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/session/gauges/GaugeManager.java b/firebase-perf/src/main/java/com/google/firebase/perf/session/gauges/GaugeManager.java index 33699409e6b..64cd5998a3a 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/session/gauges/GaugeManager.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/session/gauges/GaugeManager.java @@ -267,7 +267,6 @@ public boolean logGaugeMetadata(String sessionId, ApplicationProcessState appSta private GaugeMetadata getGaugeMetadata() { return GaugeMetadata.newBuilder() - .setProcessName(gaugeMetadataManager.getProcessName()) .setDeviceRamSizeKb(gaugeMetadataManager.getDeviceRamSizeKb()) .setMaxAppJavaHeapMemoryKb(gaugeMetadataManager.getMaxAppJavaHeapMemoryKb()) .setMaxEncouragedAppJavaHeapMemoryKb( diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/session/gauges/GaugeMetadataManager.java b/firebase-perf/src/main/java/com/google/firebase/perf/session/gauges/GaugeMetadataManager.java index 18ec46e15df..6b4466dfc35 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/session/gauges/GaugeMetadataManager.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/session/gauges/GaugeMetadataManager.java @@ -19,7 +19,6 @@ import android.content.Context; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.google.firebase.perf.logging.AndroidLogger; import com.google.firebase.perf.util.StorageUnit; @@ -28,7 +27,6 @@ import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; -import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -43,7 +41,6 @@ class GaugeMetadataManager { private final Runtime runtime; private final ActivityManager activityManager; private final MemoryInfo memoryInfo; - private final String currentProcessName; private final Context appContext; GaugeMetadataManager(Context appContext) { @@ -57,15 +54,6 @@ class GaugeMetadataManager { this.activityManager = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE); memoryInfo = new ActivityManager.MemoryInfo(); activityManager.getMemoryInfo(memoryInfo); - - // Assign the current process name here to avoid iterating through all the running processes - // each time getCurrentProcessName() is called. - currentProcessName = getCurrentProcessName(); - } - - /** Returns the name of the process FirebaseApp is associated with. */ - public String getProcessName() { - return currentProcessName; } /** @@ -112,23 +100,4 @@ int readTotalRAM(String procFileName) { return 0; } - - /** Returns the name of the process the Application is associated with. */ - private String getCurrentProcessName() { - int myProcessPid = android.os.Process.myPid(); - - @Nullable - List runningAppProcessInfos = - activityManager.getRunningAppProcesses(); - - if (runningAppProcessInfos != null) { - for (ActivityManager.RunningAppProcessInfo processInfo : runningAppProcessInfos) { - if (processInfo.pid == myProcessPid) { - return processInfo.processName; - } - } - } - - return appContext.getPackageName(); - } } diff --git a/firebase-perf/src/main/proto/firebase/perf/v1/perf_metric.proto b/firebase-perf/src/main/proto/firebase/perf/v1/perf_metric.proto index 8f4a0fd10da..8da196c0281 100644 --- a/firebase-perf/src/main/proto/firebase/perf/v1/perf_metric.proto +++ b/firebase-perf/src/main/proto/firebase/perf/v1/perf_metric.proto @@ -266,11 +266,8 @@ message AndroidMemoryReading { // // Next tag: 7 message GaugeMetadata { - // The process in which Firebase instance is initialized and collecting data. - // Fireperf sdk collects information in the context of a process (instead of - // the whole app). The process name helps developer identifies which process - // are the gauge data coming from. - optional string process_name = 1; + // Deprecated on 09/2022. + optional string process_name = 1 [deprecated = true]; // Clock rate of the cpu of the device, in kHz. optional int32 cpu_clock_rate_khz = 2; diff --git a/firebase-perf/src/test/java/com/google/firebase/perf/config/RemoteConfigManagerTest.java b/firebase-perf/src/test/java/com/google/firebase/perf/config/RemoteConfigManagerTest.java index 9855d3cfe62..af1b971d9a1 100644 --- a/firebase-perf/src/test/java/com/google/firebase/perf/config/RemoteConfigManagerTest.java +++ b/firebase-perf/src/test/java/com/google/firebase/perf/config/RemoteConfigManagerTest.java @@ -25,6 +25,7 @@ import androidx.annotation.NonNull; import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.TaskCompletionSource; +import com.google.common.util.concurrent.MoreExecutors; import com.google.firebase.inject.Provider; import com.google.firebase.perf.FirebasePerformanceTestBase; import com.google.firebase.perf.provider.FirebasePerfProvider; @@ -48,11 +49,16 @@ public final class RemoteConfigManagerTest extends FirebasePerformanceTestBase { private static final String FIREPERF_FRC_NAMESPACE_NAME = "fireperf"; + private static final FirebaseRemoteConfigValue TRUE_VALUE = + new RemoteConfigValueImplForTest("true"); + private static final FirebaseRemoteConfigValue FALSE_VALUE = + new RemoteConfigValueImplForTest("false"); @Mock private FirebaseRemoteConfig mockFirebaseRemoteConfig; @Mock private RemoteConfigComponent mockFirebaseRemoteConfigComponent; @Mock private Provider mockFirebaseRemoteConfigProvider; + private DeviceCacheManager cacheManager; private FakeScheduledExecutorService fakeExecutor; @Before @@ -60,6 +66,8 @@ public void setUp() { initMocks(this); fakeExecutor = new FakeScheduledExecutorService(); + // DeviceCacheManager initialization requires immediate blocking task execution in its executor + cacheManager = new DeviceCacheManager(MoreExecutors.newDirectExecutorService()); when(mockFirebaseRemoteConfigProvider.get()).thenReturn(mockFirebaseRemoteConfigComponent); when(mockFirebaseRemoteConfigComponent.get(FIREPERF_FRC_NAMESPACE_NAME)) @@ -230,6 +238,29 @@ public void getString_validFrcValue_updatesWithNewValue() { assertThat(testRemoteConfigManager.getString("some_key3").isAvailable()).isFalse(); } + @Test + public void syncConfigValues_savesNewlyFetchedValueToDeviceCache() { + Map configs = new HashMap<>(); + ConfigurationConstants.ExperimentTTID flag = + ConfigurationConstants.ExperimentTTID.getInstance(); + configs.put(flag.getRemoteConfigFlag(), TRUE_VALUE); + RemoteConfigManager testRemoteConfigManager = setupTestRemoteConfigManager(configs); + + assertThat(cacheManager.getBoolean(flag.getDeviceCacheFlag()).isAvailable()).isFalse(); + + configs.put(flag.getRemoteConfigFlag(), FALSE_VALUE); + testRemoteConfigManager.syncConfigValues(configs); + + assertThat(cacheManager.getBoolean(flag.getDeviceCacheFlag()).isAvailable()).isTrue(); + assertThat(cacheManager.getBoolean(flag.getDeviceCacheFlag()).get()).isFalse(); + + configs.put(flag.getRemoteConfigFlag(), TRUE_VALUE); + testRemoteConfigManager.syncConfigValues(configs); + + assertThat(cacheManager.getBoolean(flag.getDeviceCacheFlag()).isAvailable()).isTrue(); + assertThat(cacheManager.getBoolean(flag.getDeviceCacheFlag()).get()).isTrue(); + } + @Test public void getRemoteConfigValueOrDefaultLong_invalidFrcValue_returnsDefaultValue() { Map configs = createDefaultRcConfigMap(); @@ -889,10 +920,13 @@ private RemoteConfigManager setupTestRemoteConfigManager( when(mockFirebaseRemoteConfig.getAll()).thenReturn(configs); if (initializeFrc) { return new RemoteConfigManager( - fakeExecutor, mockFirebaseRemoteConfig, appStartConfigFetchDelayInMs); + cacheManager, fakeExecutor, mockFirebaseRemoteConfig, appStartConfigFetchDelayInMs); } else { return new RemoteConfigManager( - fakeExecutor, /* firebaseRemoteConfig= */ null, appStartConfigFetchDelayInMs); + cacheManager, + fakeExecutor, + /* firebaseRemoteConfig= */ null, + appStartConfigFetchDelayInMs); } } diff --git a/firebase-perf/src/test/java/com/google/firebase/perf/metrics/AppStartTraceTest.java b/firebase-perf/src/test/java/com/google/firebase/perf/metrics/AppStartTraceTest.java index c1f975754e5..e705a145aed 100644 --- a/firebase-perf/src/test/java/com/google/firebase/perf/metrics/AppStartTraceTest.java +++ b/firebase-perf/src/test/java/com/google/firebase/perf/metrics/AppStartTraceTest.java @@ -14,19 +14,27 @@ package com.google.firebase.perf.metrics; +import static com.google.common.truth.Truth.assertThat; import static com.google.firebase.perf.util.TimerTest.getElapsedRealtimeMicros; +import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; +import static org.robolectric.Shadows.shadowOf; import android.app.Activity; import android.content.pm.ProviderInfo; import android.os.Bundle; +import android.os.Looper; +import android.os.Process; +import android.os.SystemClock; +import android.view.View; import androidx.test.core.app.ApplicationProvider; import com.google.firebase.perf.FirebasePerformanceTestBase; +import com.google.firebase.perf.config.ConfigResolver; import com.google.firebase.perf.provider.FirebasePerfProvider; import com.google.firebase.perf.session.SessionManager; import com.google.firebase.perf.transport.TransportManager; @@ -36,6 +44,7 @@ import com.google.firebase.perf.v1.ApplicationProcessState; import com.google.firebase.perf.v1.TraceMetric; import com.google.testing.timing.FakeScheduledExecutorService; +import java.time.Duration; import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.Assert; @@ -48,13 +57,18 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; +import org.robolectric.shadows.ShadowSystemClock; /** Unit tests for {@link AppStartTrace}. */ @RunWith(RobolectricTestRunner.class) +@LooperMode(LooperMode.Mode.PAUSED) public class AppStartTraceTest extends FirebasePerformanceTestBase { @Mock private Clock clock; @Mock private TransportManager transportManager; + @Mock private ConfigResolver configResolver; @Mock private Activity activity1; @Mock private Activity activity2; @Mock private Bundle bundle; @@ -94,7 +108,8 @@ public void reset() { @Test public void testLaunchActivity() { FakeScheduledExecutorService fakeExecutorService = new FakeScheduledExecutorService(); - AppStartTrace trace = new AppStartTrace(transportManager, clock, fakeExecutorService); + AppStartTrace trace = + new AppStartTrace(transportManager, clock, configResolver, fakeExecutorService); // first activity goes through onCreate()->onStart()->onResume() state change. currentTime = 1; trace.onActivityCreated(activity1, bundle); @@ -171,7 +186,8 @@ private void verifyFinalState( @Test public void testInterleavedActivity() { FakeScheduledExecutorService fakeExecutorService = new FakeScheduledExecutorService(); - AppStartTrace trace = new AppStartTrace(transportManager, clock, fakeExecutorService); + AppStartTrace trace = + new AppStartTrace(transportManager, clock, configResolver, fakeExecutorService); // first activity onCreate() currentTime = 1; trace.onActivityCreated(activity1, bundle); @@ -206,7 +222,8 @@ public void testInterleavedActivity() { @Test public void testDelayedAppStart() { FakeScheduledExecutorService fakeExecutorService = new FakeScheduledExecutorService(); - AppStartTrace trace = new AppStartTrace(transportManager, clock, fakeExecutorService); + AppStartTrace trace = + new AppStartTrace(transportManager, clock, configResolver, fakeExecutorService); // Delays activity creation after 1 minute from app start time. currentTime = appStart.getMicros() + TimeUnit.MINUTES.toMicros(1) + 1; trace.onActivityCreated(activity1, bundle); @@ -227,7 +244,8 @@ public void testDelayedAppStart() { @Test public void testStartFromBackground() { FakeScheduledExecutorService fakeExecutorService = new FakeScheduledExecutorService(); - AppStartTrace trace = new AppStartTrace(transportManager, clock, fakeExecutorService); + AppStartTrace trace = + new AppStartTrace(transportManager, clock, configResolver, fakeExecutorService); trace.setIsStartFromBackground(); trace.onActivityCreated(activity1, bundle); Assert.assertNull(trace.getOnCreateTime()); @@ -261,4 +279,43 @@ public void testFirebasePerfProviderOnAttachInfo_initializesGaugeCollection() { Assert.assertEquals(oldSessionId, SessionManager.getInstance().perfSession().sessionId()); verify(mockPerfSession, times(2)).isGaugeAndEventCollectionEnabled(); } + + @Test + @Config(sdk = 26) + public void timeToInitialDisplay_isLogged() { + // Test setup + when(clock.getTime()).thenCallRealMethod(); // Use robolectric shadows to manipulate time + View testView = new View(ApplicationProvider.getApplicationContext()); + when(activity1.findViewById(android.R.id.content)).thenReturn(testView); + when(configResolver.getIsExperimentTTIDEnabled()).thenReturn(true); + FakeScheduledExecutorService fakeExecutorService = new FakeScheduledExecutorService(); + AppStartTrace trace = + new AppStartTrace(transportManager, clock, configResolver, fakeExecutorService); + + // Simulate resume and manually stepping time forward + ShadowSystemClock.advanceBy(Duration.ofMillis(1000)); + long resumeTime = TimeUnit.NANOSECONDS.toMicros(SystemClock.elapsedRealtimeNanos()); + trace.onActivityCreated(activity1, bundle); + trace.onActivityStarted(activity1); + trace.onActivityResumed(activity1); + fakeExecutorService.runAll(); + verify(transportManager, times(1)) + .log(isA(TraceMetric.class), isA(ApplicationProcessState.class)); + + // Simulate draw and manually stepping time forward + ShadowSystemClock.advanceBy(Duration.ofMillis(1000)); + long drawTime = TimeUnit.NANOSECONDS.toMicros(SystemClock.elapsedRealtimeNanos()); + testView.getViewTreeObserver().dispatchOnDraw(); + shadowOf(Looper.getMainLooper()).idle(); + fakeExecutorService.runNext(); + verify(transportManager, times(2)) + .log(traceArgumentCaptor.capture(), isA(ApplicationProcessState.class)); + + // Verify ttid trace is being logged + TraceMetric ttid = traceArgumentCaptor.getValue(); + long appStartTime = TimeUnit.MILLISECONDS.toMicros(Process.getStartElapsedRealtime()); + assertThat(ttid.getName()).isEqualTo("_experiment_app_start_ttid"); + assertThat(ttid.getDurationUs()).isNotEqualTo(resumeTime - appStartTime); + assertThat(ttid.getDurationUs()).isEqualTo(drawTime - appStartTime); + } } diff --git a/firebase-perf/src/test/java/com/google/firebase/perf/metrics/validator/FirebasePerfGaugeManagerValidatorTest.java b/firebase-perf/src/test/java/com/google/firebase/perf/metrics/validator/FirebasePerfGaugeManagerValidatorTest.java index cbc2137f541..02f0ef21314 100644 --- a/firebase-perf/src/test/java/com/google/firebase/perf/metrics/validator/FirebasePerfGaugeManagerValidatorTest.java +++ b/firebase-perf/src/test/java/com/google/firebase/perf/metrics/validator/FirebasePerfGaugeManagerValidatorTest.java @@ -56,7 +56,6 @@ public void testGaugeMetricIsValid() { // Construct GaugeMetadata GaugeMetadata gaugeMetadata = createValidGaugeMetadata( - "processName", /* deviceRamSizeKb= */ 2000, /* maxAppJavaHeapMemoryKb= */ 1000, /* maxEncouragedAppJavaHeapMemoryKb= */ 800); @@ -115,7 +114,6 @@ public void testGaugeMetricWithOnlyMemoryMetricIsValid() { public void testGaugeMetricWithOnlyGaugeMetadataIsValid() { GaugeMetadata gaugeMetadata = createValidGaugeMetadata( - "processName", /* deviceRamSizeKb= */ 2000, /* maxAppJavaHeapMemoryKb= */ 1000, /* maxEncouragedAppJavaHeapMemoryKb= */ 800); @@ -134,7 +132,6 @@ public void testGaugeMetricWithOnlyGaugeMetadataIsValid() { public void testGaugeMetadataWithoutMaxJavaHeapIsNotValid() { GaugeMetadata gaugeMetadata = GaugeMetadata.newBuilder() - .setProcessName("processName") .setDeviceRamSizeKb(2000) .setMaxEncouragedAppJavaHeapMemoryKb(800) .build(); @@ -202,12 +199,8 @@ private AndroidMemoryReading createValidAndroidMetricReading(int currentUsedAppJ } private GaugeMetadata createValidGaugeMetadata( - String processName, - int deviceRamSizeKb, - int maxAppJavaHeapMemoryKb, - int maxEncouragedAppJavaHeapMemoryKb) { + int deviceRamSizeKb, int maxAppJavaHeapMemoryKb, int maxEncouragedAppJavaHeapMemoryKb) { GaugeMetadata.Builder fakeGaugeMetadataBuilder = GaugeMetadata.newBuilder(); - fakeGaugeMetadataBuilder.setProcessName(processName); fakeGaugeMetadataBuilder.setDeviceRamSizeKb(deviceRamSizeKb); fakeGaugeMetadataBuilder.setMaxAppJavaHeapMemoryKb(maxAppJavaHeapMemoryKb); fakeGaugeMetadataBuilder.setMaxEncouragedAppJavaHeapMemoryKb(maxEncouragedAppJavaHeapMemoryKb); diff --git a/firebase-perf/src/test/java/com/google/firebase/perf/session/gauges/GaugeManagerTest.java b/firebase-perf/src/test/java/com/google/firebase/perf/session/gauges/GaugeManagerTest.java index 7acc4b2b97d..5090d66c8b9 100644 --- a/firebase-perf/src/test/java/com/google/firebase/perf/session/gauges/GaugeManagerTest.java +++ b/firebase-perf/src/test/java/com/google/firebase/perf/session/gauges/GaugeManagerTest.java @@ -637,7 +637,6 @@ public void testStartGaugeManagerWithNewSessionIdAndNewAppState() { @Test public void testLogGaugeMetadataSendDataToTransport() { - when(fakeGaugeMetadataManager.getProcessName()).thenReturn("processName"); when(fakeGaugeMetadataManager.getDeviceRamSizeKb()).thenReturn(2000); when(fakeGaugeMetadataManager.getMaxAppJavaHeapMemoryKb()).thenReturn(1000); when(fakeGaugeMetadataManager.getMaxEncouragedAppJavaHeapMemoryKb()).thenReturn(800); @@ -649,7 +648,6 @@ public void testLogGaugeMetadataSendDataToTransport() { GaugeMetadata recordedGaugeMetadata = recordedGaugeMetric.getGaugeMetadata(); assertThat(recordedGaugeMetric.getSessionId()).isEqualTo("sessionId"); - assertThat(recordedGaugeMetadata.getProcessName()).isEqualTo("processName"); assertThat(recordedGaugeMetadata.getDeviceRamSizeKb()) .isEqualTo(fakeGaugeMetadataManager.getDeviceRamSizeKb()); @@ -699,7 +697,6 @@ public void testLogGaugeMetadataLogsAfterApplicationContextIsSet() { GaugeMetadata recordedGaugeMetadata = recordedGaugeMetric.getGaugeMetadata(); assertThat(recordedGaugeMetric.getSessionId()).isEqualTo("sessionId"); - assertThat(recordedGaugeMetadata.hasProcessName()).isTrue(); } @Test diff --git a/firebase-perf/src/test/java/com/google/firebase/perf/session/gauges/GaugeMetadataManagerTest.java b/firebase-perf/src/test/java/com/google/firebase/perf/session/gauges/GaugeMetadataManagerTest.java index 07366aa2a20..292747121dd 100644 --- a/firebase-perf/src/test/java/com/google/firebase/perf/session/gauges/GaugeMetadataManagerTest.java +++ b/firebase-perf/src/test/java/com/google/firebase/perf/session/gauges/GaugeMetadataManagerTest.java @@ -16,13 +16,10 @@ import static com.google.common.truth.Truth.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; import static org.robolectric.Shadows.shadowOf; import android.app.ActivityManager; -import android.app.ActivityManager.RunningAppProcessInfo; import android.content.Context; import android.os.Environment; import androidx.test.core.app.ApplicationProvider; @@ -32,8 +29,6 @@ import java.io.IOException; import java.io.Writer; import java.nio.file.Files; -import java.util.ArrayList; -import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -78,38 +73,6 @@ private void mockMemory() { shadowOf(activityManager).setMemoryClass(RUNTIME_MAX_ENCOURAGED_MEMORY_MB); } - @Test - public void testInitialization_getProcessNameReturnsNull_doesNotCrash() { - ActivityManager activityManagerPartialMock = spy(activityManager); - when(activityManagerPartialMock.getRunningAppProcesses()).thenReturn(null); - - assertThat(new GaugeMetadataManager(runtime, appContext)).isNotNull(); - } - - @Test - public void testGetProcessName_noProcessInfoList_returnsPackageName() { - shadowOf(activityManager).setProcesses(new ArrayList<>()); - assertThat(new GaugeMetadataManager(runtime, appContext).getProcessName()) - .isEqualTo(appContext.getPackageName()); - } - - @Test - public void testGetProcessName_processListWithoutCurrentPid_returnsPackageName() { - shadowOf(activityManager) - .setProcesses( - generateFakeAppProcessInfoListThatContainsPid(android.os.Process.myPid() + 100)); - assertThat(new GaugeMetadataManager(runtime, appContext).getProcessName()) - .isEqualTo(appContext.getPackageName()); - } - - @Test - public void testGetProcessName_processListWithCurrentPid_returnsProcessName() { - shadowOf(activityManager) - .setProcesses(generateFakeAppProcessInfoListThatContainsPid(android.os.Process.myPid())); - assertThat(new GaugeMetadataManager(runtime, appContext).getProcessName()) - .isEqualTo("fakeProcessName"); - } - @Test public void testGetMaxAppJavaHeapMemory_returnsExpectedValue() { assertThat(testGaugeMetadataManager.getMaxAppJavaHeapMemoryKb()).isGreaterThan(0); @@ -146,17 +109,6 @@ private String createFakeMemInfoFile() throws IOException { return file.getAbsolutePath(); } - private List generateFakeAppProcessInfoListThatContainsPid(int pid) { - ActivityManager.RunningAppProcessInfo fakeProcessInfoList = new RunningAppProcessInfo(); - fakeProcessInfoList.pid = pid; - fakeProcessInfoList.processName = "fakeProcessName"; - - List processInfoList = new ArrayList<>(); - processInfoList.add(fakeProcessInfoList); - - return processInfoList; - } - private static final String MEM_INFO_CONTENTS = "MemTotal: " + DEVICE_RAM_SIZE_KB diff --git a/firebase-segmentation/src/main/java/com/google/firebase/segmentation/FirebaseSegmentationRegistrar.java b/firebase-segmentation/src/main/java/com/google/firebase/segmentation/FirebaseSegmentationRegistrar.java index c69385a9cba..d005b206677 100644 --- a/firebase-segmentation/src/main/java/com/google/firebase/segmentation/FirebaseSegmentationRegistrar.java +++ b/firebase-segmentation/src/main/java/com/google/firebase/segmentation/FirebaseSegmentationRegistrar.java @@ -26,12 +26,14 @@ /** @hide */ public class FirebaseSegmentationRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-segmentation"; @Override @NonNull public List> getComponents() { return Arrays.asList( Component.builder(FirebaseSegmentation.class) + .name(LIBRARY_NAME) .add(Dependency.required(FirebaseApp.class)) .add(Dependency.required(FirebaseInstallationsApi.class)) .factory( @@ -39,6 +41,6 @@ public List> getComponents() { new FirebaseSegmentation( c.get(FirebaseApp.class), c.get(FirebaseInstallationsApi.class))) .build(), - LibraryVersionComponent.create("fire-segmentation", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/firebase-storage/CHANGELOG.md b/firebase-storage/CHANGELOG.md index c45a2ac5184..7ffa4afeff7 100644 --- a/firebase-storage/CHANGELOG.md +++ b/firebase-storage/CHANGELOG.md @@ -1,35 +1,179 @@ +# Unreleased + +# 20.0.3 +- [fixed] Fixed an issue that caused infinite number of retries with no exponential + backoff for `uploadChunk` + +# 20.2.0 +* [unchanged] Updated to accommodate the release of the updated + [firebase_storage_full] Kotlin extensions library. + + +## Kotlin +The Kotlin extensions library transitively includes the updated + `firebase-storage` library. The Kotlin extensions library has the following + additional updates: + +* [feature] Firebase now supports Kotlin coroutines. + With this release, we added + [`kotlinx-coroutines-play-services`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-play-services/){: .external} + to `firebase-storage-ktx` as a transitive dependency, which exposes the + `Task.await()` suspend function to convert a + [`Task`](https://developers.google.com/android/guides/tasks) into a Kotlin + coroutine. + +* [feature] Added + [`StorageTask.taskState`](/docs/reference/kotlin/com/google/firebase/storage/ktx/package-summary#taskState) + Kotlin Flows to monitor the progress of an upload or download `Task`. + +# 20.0.2 +* [changed] Updated dependency of `play-services-basement` to its latest + version (v18.1.0). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-storage` library. The Kotlin extensions library has no additional +updates. + +# 20.0.1 +* [changed] Updated dependencies of `play-services-basement`, + `play-services-base`, and `play-services-tasks` to their latest versions + (v18.0.0, v18.0.1, and v18.0.1, respectively). For more information, see the + [note](#basement18-0-0_base18-0-1_tasks18-0-1) at the top of this release + entry. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-storage` library. The Kotlin extensions library has no additional +updates. + +# 20.0.0 +* [feature] Added abuse reduction features. + +* [feature] Added the ability to connect to the [firebase_storage] emulator. + +* [changed] Internal changes to support dynamic feature modules. + +* [changed] Internal infrastructure improvements. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-storage` library. The Kotlin extensions library has no additional +updates. + # 19.2.2 - [fixed] Fixed an issue that caused the SDK to report incorrect values for - "getTotalByteCount()" after a download was paused and resumed. +[`getTotalByteCount()`](docs/reference/android/com/google/firebase/storage/FileDownloadTask.TaskSnapshot#getTotalByteCount()) +after a download was paused and resumed. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-storage` library. The Kotlin extensions library has no additional +updates. # 19.2.1 - [fixed] Fixed an issue that caused the SDK to crash if the download location - was deleted before the download completed. Instead, the download now fails. + was deleted before the download completed. Instead, the download now fails. + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-storage` library. The Kotlin extensions library has no additional +updates. -# 19.0.2 -- [fixed] Fixed an encoding issue in `list()/listAll()` that caused us to miss - entries for folders that contained special characters. + + + + +# 19.2.0 +- [changed] Updated to support improvements in the KTX library (see below). + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-storage` library and has the following additional updates: + +- [feature] Added API support for destructuring of + [`TaskSnapshot`](/docs/reference/kotlin/com/google/firebase/storage/StreamDownloadTask.TaskSnapshot) + and + [`ListResult`](/docs/reference/kotlin/com/google/firebase/storage/ListResult). + +# 19.1.1 +- [changed] Internal changes to ensure functionality alignment with other SDK releases. + + + +## Kotlin +The Kotlin extensions library transitively includes the updated +`firebase-storage` library. The Kotlin extensions library has no additional +updates. + +# 19.1.0 +- [feature] Added `getCacheControl()`, `getContentDisposition()`, + `getContentEncoding()`, `getContentLanguage()`, and `getContentType()` to + [`StorageMetadata.Builder`](/docs/reference/android/com/google/firebase/storage/StorageMetadata.Builder) + to provide access to the current state of the metadata. + +- [fixed] Fixed an encoding issue in + [`StorageReference.list()`](/docs/reference/android/com/google/firebase/storage/StorageReference.html#list(int)) + that caused the API to miss entries for prefixes that contained special + characters. + + +## Kotlin +* [feature] The beta release of a [firebase_storage_full] Android library + with Kotlin extensions is now available. The Kotlin extensions library + transitively includes the base `firebase-storage` library. To learn more, + visit the + [[firebase_storage_full] KTX documentation](/docs/reference/kotlin/com/google/firebase/storage/ktx/package-summary). # 19.0.1 -- [fixed] `listAll()` now propagates the error messages if the List operation - was denied by a Security Rule. +- [fixed] [`StorageReference.listAll()`](/docs/reference/android/com/google/firebase/storage/StorageReference.html#listAll()) + now propagates the error messages if the List operation was denied by a + Security Rule. # 19.0.0 -- [changed] Added missing nullability annotations for better Kotlin interop. -- [internal] Removed ``@PublicApi` annotations as they are no longer enforced - and have no semantic meaning. +* [changed] Versioned to add nullability annotations to improve the Kotlin + developer experience. No other changes. + +# 18.1.1 +- [changed] Internal changes to ensure functionality alignment with other SDK + releases. # 18.1.0 -- [feature] Added `StorageReference.list()` and `StorageReference.listAll()`, +* [feature] Added + [`StorageReference.list()`](/docs/reference/android/com/google/firebase/storage/StorageReference.html#list(int)) + and [`StorageReference.listAll()`](/docs/reference/android/com/google/firebase/storage/StorageReference.html#listAll()), which allows developers to list the files and folders under the given StorageReference. -- [changed] Added validation to `StorageReference.getDownloadUrl()` and - `StorageReference.getMetadata()` to return an error if the reference is the - root of the bucket. +* [changed] Added validation to + [`StorageReference.getDownloadUrl()`](/docs/reference/android/com/google/firebase/storage/StorageReference.html#getDownloadUrl()) + and [`StorageReference.getMetadata()`](/docs/reference/android/com/google/firebase/storage/StorageReference.html#getMetadata()) + to return an error if the reference is the root of the bucket. # 17.0.0 -- [internal] Updated the SDK initialization process and removed usages of - deprecated methods. -- [changed] Added `@RestrictTo` annotations to discourage the use of APIs that - are not public. This affects internal APIs that were previously obfuscated - and are not mentioned in our documentation. +* [changed] Internal changes that rely on an updated API to obtain + authentication credentials. If you use [firebase_auth], update to + `firebase-auth` v17.0.0 or later to ensure functionality alignment. + + + +# 16.0.2 +* [fixed] This release includes minor fixes and improvements. + +# 16.0.1 +* [feature] Added support for `onSuccessTask()` and `addOnCanceledListener()` + to [`StorageTask`](/docs/reference/android/com/google/firebase/storage/StorageTask), + [`UploadTask`](/docs/reference/android/com/google/firebase/storage/UploadTask), + [`StreamDownloadTask`](/docs/reference/android/com/google/firebase/storage/StreamDownloadTask), + and [`FileDownloadTask`](/docs/reference/android/com/google/firebase/storage/FileDownloadTask). + +* [changed] Removed the deprecated `StorageMetadata.getDownloadUrl()` and + `UploadTask.TaskSnapshot.getDownloadUrl()` methods. To get a current download + URL, use + [`StorageReference.getDownloadUr()`](/docs/reference/android/com/google/firebase/storage/StorageReference.html#getDownloadUrl()). + diff --git a/firebase-storage/ktx/api.txt b/firebase-storage/ktx/api.txt index 104fa68d25b..20f84128b45 100644 --- a/firebase-storage/ktx/api.txt +++ b/firebase-storage/ktx/api.txt @@ -15,11 +15,27 @@ package com.google.firebase.storage.ktx { method @Nullable public static operator String component3(@NonNull com.google.firebase.storage.ListResult); method @Nullable public static operator android.net.Uri component4(@NonNull com.google.firebase.storage.UploadTask.TaskSnapshot); method @NonNull public static com.google.firebase.storage.FirebaseStorage getStorage(@NonNull com.google.firebase.ktx.Firebase); + method @NonNull public static kotlinx.coroutines.flow.Flow> getTaskState(@NonNull com.google.firebase.storage.StorageTask); method @NonNull public static com.google.firebase.storage.FirebaseStorage storage(@NonNull com.google.firebase.ktx.Firebase, @NonNull String url); method @NonNull public static com.google.firebase.storage.FirebaseStorage storage(@NonNull com.google.firebase.ktx.Firebase, @NonNull com.google.firebase.FirebaseApp app); method @NonNull public static com.google.firebase.storage.FirebaseStorage storage(@NonNull com.google.firebase.ktx.Firebase, @NonNull com.google.firebase.FirebaseApp app, @NonNull String url); method @NonNull public static com.google.firebase.storage.StorageMetadata storageMetadata(@NonNull kotlin.jvm.functions.Function1 init); } + public abstract class TaskState { + } + + public static final class TaskState.InProgress extends com.google.firebase.storage.ktx.TaskState { + ctor public TaskState.InProgress(@Nullable T snapshot); + method public T getSnapshot(); + property public final T snapshot; + } + + public static final class TaskState.Paused extends com.google.firebase.storage.ktx.TaskState { + ctor public TaskState.Paused(@Nullable T snapshot); + method public T getSnapshot(); + property public final T snapshot; + } + } diff --git a/firebase-storage/ktx/ktx.gradle b/firebase-storage/ktx/ktx.gradle index e45840aadf5..5669f37f715 100644 --- a/firebase-storage/ktx/ktx.gradle +++ b/firebase-storage/ktx/ktx.gradle @@ -17,6 +17,8 @@ plugins { id 'kotlin-android' } +group = "com.google.firebase" + firebaseLibrary { releaseWith project(':firebase-storage') publishJavadoc = true @@ -61,6 +63,7 @@ dependencies { implementation project(':firebase-storage') implementation 'androidx.annotation:annotation:1.1.0' implementation 'com.google.android.gms:play-services-tasks:18.0.1' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" androidTestImplementation 'junit:junit:4.12' androidTestImplementation "com.google.truth:truth:$googleTruthVersion" diff --git a/firebase-storage/ktx/src/main/kotlin/com/google/firebase/storage/ktx/Storage.kt b/firebase-storage/ktx/src/main/kotlin/com/google/firebase/storage/ktx/Storage.kt index d560b1232ad..915f5d6f85e 100644 --- a/firebase-storage/ktx/src/main/kotlin/com/google/firebase/storage/ktx/Storage.kt +++ b/firebase-storage/ktx/src/main/kotlin/com/google/firebase/storage/ktx/Storage.kt @@ -15,6 +15,7 @@ package com.google.firebase.storage.ktx import androidx.annotation.Keep +import com.google.android.gms.tasks.OnCompleteListener import com.google.firebase.FirebaseApp import com.google.firebase.components.Component import com.google.firebase.components.ComponentRegistrar @@ -23,10 +24,19 @@ import com.google.firebase.platforminfo.LibraryVersionComponent import com.google.firebase.storage.FileDownloadTask import com.google.firebase.storage.FirebaseStorage import com.google.firebase.storage.ListResult +import com.google.firebase.storage.OnPausedListener +import com.google.firebase.storage.OnProgressListener import com.google.firebase.storage.StorageMetadata import com.google.firebase.storage.StorageReference +import com.google.firebase.storage.StorageTask +import com.google.firebase.storage.StorageTaskScheduler import com.google.firebase.storage.StreamDownloadTask import com.google.firebase.storage.UploadTask +import kotlinx.coroutines.cancel +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.channels.trySendBlocking +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow /** Returns the [FirebaseStorage] instance of the default [FirebaseApp]. */ val Firebase.storage: FirebaseStorage @@ -133,6 +143,47 @@ operator fun ListResult.component2(): List = prefixes */ operator fun ListResult.component3(): String? = pageToken +/** + * Starts listening to this task's progress and emits its values via a [Flow]. + * + * - When the returned flow starts being collected, it attaches the following listeners: + * [OnProgressListener], [OnPausedListener], [OnCompleteListener]. + * - When the flow completes the listeners will be removed. + */ +val .SnapshotBase> StorageTask.taskState: Flow> + get() = callbackFlow { + val progressListener = OnProgressListener { snapshot -> + StorageTaskScheduler.getInstance().scheduleCallback { + trySendBlocking(TaskState.InProgress(snapshot)) + } + } + val pauseListener = OnPausedListener { snapshot -> + StorageTaskScheduler.getInstance().scheduleCallback { + trySendBlocking(TaskState.Paused(snapshot)) + } + } + + // Only used to close or cancel the Flows, doesn't send any values + val completionListener = OnCompleteListener { task -> + if (task.isSuccessful) { + close() + } else { + val exception = task.exception + cancel("Error getting the TaskState", exception) + } + } + + addOnProgressListener(progressListener) + addOnPausedListener(pauseListener) + addOnCompleteListener(completionListener) + + awaitClose { + removeOnProgressListener(progressListener) + removeOnPausedListener(pauseListener) + removeOnCompleteListener(completionListener) + } + } + internal const val LIBRARY_NAME: String = "fire-stg-ktx" /** @suppress */ diff --git a/firebase-storage/ktx/src/main/kotlin/com/google/firebase/storage/ktx/TaskState.kt b/firebase-storage/ktx/src/main/kotlin/com/google/firebase/storage/ktx/TaskState.kt new file mode 100644 index 00000000000..8b8454c8efb --- /dev/null +++ b/firebase-storage/ktx/src/main/kotlin/com/google/firebase/storage/ktx/TaskState.kt @@ -0,0 +1,16 @@ +package com.google.firebase.storage.ktx + +/** + * Used to emit events about the progress of storage tasks. + */ +abstract class TaskState private constructor() { + /** + * Called periodically as data is transferred and can be used to populate an upload/download indicator. + */ + class InProgress(val snapshot: T) : TaskState() + + /** + * Called any time the upload/download is paused. + */ + class Paused(val snapshot: T) : TaskState() +} diff --git a/firebase-storage/src/main/java/com/google/firebase/storage/FirebaseStorage.java b/firebase-storage/src/main/java/com/google/firebase/storage/FirebaseStorage.java index c646ddbff1d..a9ef7841045 100644 --- a/firebase-storage/src/main/java/com/google/firebase/storage/FirebaseStorage.java +++ b/firebase-storage/src/main/java/com/google/firebase/storage/FirebaseStorage.java @@ -53,6 +53,7 @@ public class FirebaseStorage { @Nullable private final Provider mAppCheckProvider; @Nullable private final String mBucketName; private long sMaxUploadRetry = 10 * DateUtils.MINUTE_IN_MILLIS; // 10 * 60 * 1000 + private long sMaxChunkUploadRetry = DateUtils.MINUTE_IN_MILLIS; // 60 * 1000 private long sMaxDownloadRetry = 10 * DateUtils.MINUTE_IN_MILLIS; // 10 * 60 * 1000 private long sMaxQueryRetry = 2 * DateUtils.MINUTE_IN_MILLIS; // 2 * 60 * 1000 @@ -226,6 +227,25 @@ public void setMaxUploadRetryTimeMillis(long maxTransferRetryMillis) { sMaxUploadRetry = maxTransferRetryMillis; } + /** + * Returns the maximum time to retry sending a chunk if a failure occurs + * + * @return maximum time in milliseconds. Defaults to 1 minute. + */ + public long getMaxChunkUploadRetry() { + return sMaxChunkUploadRetry; + } + + /** + * Sets the maximum time to retry sending a chunk if a failure occurs + * + * @param maxChunkRetryMillis the maximum time in milliseconds. Defaults to 1 minute (60,000 + * milliseconds). + */ + public void setMaxChunkUploadRetry(long maxChunkRetryMillis) { + sMaxChunkUploadRetry = maxChunkRetryMillis; + } + /** * Returns the maximum time to retry operations other than upload and download if a failure * occurs. diff --git a/firebase-storage/src/main/java/com/google/firebase/storage/StorageRegistrar.java b/firebase-storage/src/main/java/com/google/firebase/storage/StorageRegistrar.java index 57ebbdd5d17..b3e773be2c4 100644 --- a/firebase-storage/src/main/java/com/google/firebase/storage/StorageRegistrar.java +++ b/firebase-storage/src/main/java/com/google/firebase/storage/StorageRegistrar.java @@ -30,10 +30,13 @@ @Keep @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class StorageRegistrar implements ComponentRegistrar { + private static final String LIBRARY_NAME = "fire-gcs"; + @Override public List> getComponents() { return Arrays.asList( Component.builder(FirebaseStorageComponent.class) + .name(LIBRARY_NAME) .add(Dependency.required(FirebaseApp.class)) .add(Dependency.optionalProvider(InternalAuthProvider.class)) .add(Dependency.optionalProvider(InternalAppCheckTokenProvider.class)) @@ -44,6 +47,6 @@ public List> getComponents() { c.getProvider(InternalAuthProvider.class), c.getProvider(InternalAppCheckTokenProvider.class))) .build(), - LibraryVersionComponent.create("fire-gcs", BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); } } diff --git a/firebase-storage/src/main/java/com/google/firebase/storage/StorageTaskScheduler.java b/firebase-storage/src/main/java/com/google/firebase/storage/StorageTaskScheduler.java index 27f0da2f656..d428ef3692f 100644 --- a/firebase-storage/src/main/java/com/google/firebase/storage/StorageTaskScheduler.java +++ b/firebase-storage/src/main/java/com/google/firebase/storage/StorageTaskScheduler.java @@ -62,6 +62,10 @@ public class StorageTaskScheduler { CALLBACK_QUEUE_EXECUTOR.allowCoreThreadTimeOut(true); } + public static void setCallbackQueueKeepAlive(long keepAliveTime, TimeUnit timeUnit) { + CALLBACK_QUEUE_EXECUTOR.setKeepAliveTime(keepAliveTime, timeUnit); + } + public static StorageTaskScheduler getInstance() { return sInstance; } diff --git a/firebase-storage/src/main/java/com/google/firebase/storage/UploadTask.java b/firebase-storage/src/main/java/com/google/firebase/storage/UploadTask.java index de53eb86ab8..df5ba061a80 100644 --- a/firebase-storage/src/main/java/com/google/firebase/storage/UploadTask.java +++ b/firebase-storage/src/main/java/com/google/firebase/storage/UploadTask.java @@ -14,6 +14,8 @@ package com.google.firebase.storage; +import static com.google.firebase.storage.internal.ExponentialBackoffSender.RND_MAX; + import android.content.ContentResolver; import android.content.Context; import android.net.Uri; @@ -25,10 +27,14 @@ import androidx.annotation.VisibleForTesting; import com.google.android.gms.common.api.Status; import com.google.android.gms.common.internal.Preconditions; +import com.google.android.gms.common.util.Clock; +import com.google.android.gms.common.util.DefaultClock; import com.google.firebase.appcheck.interop.InternalAppCheckTokenProvider; import com.google.firebase.auth.internal.InternalAuthProvider; import com.google.firebase.storage.internal.AdaptiveStreamBuffer; import com.google.firebase.storage.internal.ExponentialBackoffSender; +import com.google.firebase.storage.internal.Sleeper; +import com.google.firebase.storage.internal.SleeperImpl; import com.google.firebase.storage.internal.Util; import com.google.firebase.storage.network.NetworkRequest; import com.google.firebase.storage.network.ResumableUploadByteRequest; @@ -40,6 +46,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.Random; import java.util.concurrent.atomic.AtomicLong; import org.json.JSONException; @@ -72,6 +79,12 @@ public class UploadTask extends StorageTask { private volatile Exception mServerException = null; private volatile int mResultCode = 0; private volatile String mServerStatus; + private volatile long maxSleepTime; + private static final Random random = new Random(); + /*package*/ static Sleeper sleeper = new SleeperImpl(); + /*package*/ static Clock clock = DefaultClock.getInstance(); + private int sleepTime = 0; + private final int minimumSleepInterval = 1000; UploadTask(StorageReference targetRef, StorageMetadata metadata, byte[] bytes) { Preconditions.checkNotNull(targetRef); @@ -89,6 +102,7 @@ public class UploadTask extends StorageTask { new AdaptiveStreamBuffer(new ByteArrayInputStream(bytes), PREFERRED_CHUNK_SIZE); this.mIsStreamOwned = true; + this.maxSleepTime = storage.getMaxChunkUploadRetry(); mSender = new ExponentialBackoffSender( storage.getApp().getApplicationContext(), @@ -110,6 +124,7 @@ public class UploadTask extends StorageTask { this.mAppCheckProvider = storage.getAppCheckProvider(); this.mUri = file; InputStream inputStream = null; + this.maxSleepTime = storage.getMaxChunkUploadRetry(); mSender = new ExponentialBackoffSender( mStorageRef.getApp().getApplicationContext(), @@ -173,12 +188,13 @@ public class UploadTask extends StorageTask { this.mStreamBuffer = new AdaptiveStreamBuffer(stream, PREFERRED_CHUNK_SIZE); this.mIsStreamOwned = false; this.mUri = null; + this.maxSleepTime = storage.getMaxChunkUploadRetry(); mSender = new ExponentialBackoffSender( mStorageRef.getApp().getApplicationContext(), mAuthProvider, mAppCheckProvider, - mStorageRef.getStorage().getMaxUploadRetryTimeMillis()); + storage.getMaxUploadRetryTimeMillis()); } /** @return the target of the upload. */ @@ -321,15 +337,18 @@ private boolean shouldContinue() { } boolean inErrorState = mServerException != null || mResultCode < 200 || mResultCode >= 300; + long deadLine = clock.elapsedRealtime() + this.maxSleepTime; + long currentTime = clock.elapsedRealtime() + this.sleepTime; // we attempt to recover by calling recoverStatus(true) - if (inErrorState && !recoverStatus(true)) { - // we failed to recover. - if (serverStateValid()) { - tryChangeState(INTERNAL_STATE_FAILURE, false); + if (inErrorState) { + if (currentTime > deadLine || !recoverStatus(true)) { + if (serverStateValid()) { + tryChangeState(INTERNAL_STATE_FAILURE, false); + } + return false; } - return false; + sleepTime = Math.max(sleepTime * 2, minimumSleepInterval); } - return true; } @@ -410,6 +429,36 @@ private boolean recoverStatus(boolean withRetry) { return true; } + /** + * Send with a delay that uses sleepTime to delay sending a request to the server. Will reset + * sleepTime upon send success. TODO: Create an exponential backoff helper to consolidate code + * here and in ExponentialBackoffSender.java + * + * @param request to send + * @return whether the delay and send were successful + */ + private boolean delaySend(NetworkRequest request) { + try { + Log.d(TAG, "Waiting " + sleepTime + " milliseconds"); + sleeper.sleep(sleepTime + random.nextInt(RND_MAX)); + } catch (InterruptedException e) { + Log.w(TAG, "thread interrupted during exponential backoff."); + + Thread.currentThread().interrupt(); + mServerException = e; + return false; + } + boolean sendRes = send(request); + // We reset the sleepTime if the send was successful. For example, + // uploadChunk(request) // false, then sleepTime becomes 1000 + // uploadChunk(request) // false, then sleepTime becomes 2000 + // uploadChunk(request) // true, then sleepTime becomes 0 again + if (sendRes) { + sleepTime = 0; + } + return sendRes; + } + private void uploadChunk() { try { mStreamBuffer.fill(mCurrentChunkSize); @@ -425,7 +474,7 @@ private void uploadChunk() { bytesToUpload, mStreamBuffer.isFinished()); - if (!send(uploadRequest)) { + if (!delaySend(uploadRequest)) { mCurrentChunkSize = PREFERRED_CHUNK_SIZE; Log.d(TAG, "Resetting chunk size to " + mCurrentChunkSize); return; diff --git a/firebase-storage/src/main/java/com/google/firebase/storage/network/NetworkRequest.java b/firebase-storage/src/main/java/com/google/firebase/storage/network/NetworkRequest.java index e2c515c9bc9..a829df46c06 100644 --- a/firebase-storage/src/main/java/com/google/firebase/storage/network/NetworkRequest.java +++ b/firebase-storage/src/main/java/com/google/firebase/storage/network/NetworkRequest.java @@ -106,7 +106,7 @@ public static Uri getBaseUrl(@Nullable EmulatedServiceSettings emulatorSettings) return Uri.parse( "http://" + emulatorSettings.getHost() + ":" + emulatorSettings.getPort() + "/v0"); } else { - return Uri.parse("https://firebasestorage.googleapis.com/v0"); + return PROD_BASE_URL; } } diff --git a/firebase-storage/src/test/java/com/google/firebase/storage/TestUtil.java b/firebase-storage/src/test/java/com/google/firebase/storage/TestUtil.java index 41208b6ab63..4549186cfb0 100644 --- a/firebase-storage/src/test/java/com/google/firebase/storage/TestUtil.java +++ b/firebase-storage/src/test/java/com/google/firebase/storage/TestUtil.java @@ -32,6 +32,12 @@ public class TestUtil { static FirebaseApp createApp() { + /** + * Many tests require you to call the callback on the same thread that was initially + * instantiated. With the 5 second keepalive, after 5 seconds, the thread will get killed and + * eventually a new one will be created. Therefore causing many of the tests to fail. + */ + StorageTaskScheduler.setCallbackQueueKeepAlive(90, TimeUnit.SECONDS); return FirebaseApp.initializeApp( ApplicationProvider.getApplicationContext(), new FirebaseOptions.Builder() @@ -144,10 +150,10 @@ static void await(Task task, int timeout, TimeUnit timeUnit) throws Interrupt } /** - * Awaits for a Task for 3 seconds, but flushes the Robolectric scheduler to allow newly added + * Awaits for a Task for 10 seconds, but flushes the Robolectric scheduler to allow newly added * Tasks to be executed. */ static void await(Task task) throws InterruptedException { - await(task, 3, TimeUnit.SECONDS); + await(task, 10, TimeUnit.SECONDS); } } diff --git a/firebase-storage/src/test/java/com/google/firebase/storage/UploadTest.java b/firebase-storage/src/test/java/com/google/firebase/storage/UploadTest.java index 07f7dd57a95..0dfb06d4523 100644 --- a/firebase-storage/src/test/java/com/google/firebase/storage/UploadTest.java +++ b/firebase-storage/src/test/java/com/google/firebase/storage/UploadTest.java @@ -100,6 +100,36 @@ public void smallTextUpload() throws Exception { TestUtil.verifyTaskStateChanges("smallTextUpload", task.getResult().toString()); } + /** + * This test will replicate uploadChunk() returning 500's and test to make sure the retries are + * limited and using exponential backoff. If the maxretry limit is not checked, then the await + * task will time out. + * + * @throws Exception + */ + @Test + public void fileUploadWith500() throws Exception { + + System.out.println("Starting test fileUploadWith500."); + + MockConnectionFactory factory = NetworkLayerMock.ensureNetworkMock("fileUploadWith500", true); + + String filename = TEST_ASSET_ROOT + "image.jpg"; + ClassLoader classLoader = UploadTest.class.getClassLoader(); + InputStream imageStream = classLoader.getResourceAsStream(filename); + Uri sourceFile = Uri.parse("file://" + filename); + + ContentResolver resolver = ApplicationProvider.getApplicationContext().getContentResolver(); + Shadows.shadowOf(resolver).registerInputStream(sourceFile, imageStream); + + Task task = TestUploadHelper.fileUpload(sourceFile, "image.jpg"); + + TestUtil.await(task, 3, TimeUnit.MINUTES); + + factory.verifyOldMock(); + TestUtil.verifyTaskStateChanges("fileUploadWith500", task.getResult().toString()); + } + @Test public void cantUploadToRoot() throws Exception { System.out.println("Starting test cantUploadToRoot."); @@ -130,12 +160,13 @@ public void cantUploadToRoot() throws Exception { }); // TODO(mrschmidt): Lower the timeout - TestUtil.await(task, 300, TimeUnit.SECONDS); + TestUtil.await(task, 1, TimeUnit.MINUTES); try { task.getResult(); Assert.fail(); } catch (RuntimeExecutionException e) { + // Note: This test can be flaky due to the fact that the second .getCause() may be null. Assert.assertEquals(taskException.get().getCause(), e.getCause().getCause()); } @@ -263,7 +294,7 @@ public void cancelledUpload() throws Exception { Task task = TestUploadHelper.byteUploadCancel(); // TODO(mrschmidt): Lower the timeout - TestUtil.await(task, 500, TimeUnit.SECONDS); + TestUtil.await(task, 1000, TimeUnit.SECONDS); factory.verifyOldMock(); TestUtil.verifyTaskStateChanges("cancelledUpload", task.getResult().toString()); @@ -466,7 +497,7 @@ public void fileUploadRecovery() throws Exception { Task task = TestUploadHelper.fileUpload(sourceFile, "flubbertest.jpg"); - TestUtil.await(task, 5, TimeUnit.SECONDS); + TestUtil.await(task, 4, TimeUnit.MINUTES); factory.verifyOldMock(); TestUtil.verifyTaskStateChanges("fileUploadRecovery", task.getResult().toString()); @@ -489,7 +520,7 @@ public void fileUploadNoRecovery() throws Exception { Task task = TestUploadHelper.fileUpload(sourceFile, "flubbertest.jpg"); - TestUtil.await(task, 5, TimeUnit.SECONDS); + TestUtil.await(task); factory.verifyOldMock(); TestUtil.verifyTaskStateChanges("fileUploadNoRecovery", task.getResult().toString()); diff --git a/firebase-storage/src/test/resources/activitylogs/fileUploadWith500_network.txt b/firebase-storage/src/test/resources/activitylogs/fileUploadWith500_network.txt new file mode 100644 index 00000000000..9b462baf726 --- /dev/null +++ b/firebase-storage/src/test/resources/activitylogs/fileUploadWith500_network.txt @@ -0,0 +1,647 @@ + + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Header-Content-Type,image/jpeg +setRequestProperty:X-Goog-Upload-Command,start +setRequestProperty:Content-Type,application/json +setDoOutput:true +setRequestProperty:Content-Length,59 +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:200 +getHeaderFields: + null:[HTTP/1.1 200 OK] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:23 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137242316] + X-Android-Response-Source:[NETWORK 200] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242023] + X-Goog-Upload-Chunk-Granularity:[262144] + X-Goog-Upload-Control-URL:[https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable] + X-Goog-Upload-Status:[active] + X-Goog-Upload-URL:[https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/195,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V97mApXQtgaL-JK4Dg] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/195,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/195] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[success] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Offset,0 +setRequestProperty:X-Goog-Upload-Command,upload +setDoOutput:true +setRequestProperty:Content-Length,262144 +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:500 +getHeaderFields: + null:[HTTP/1.1 500 INTERNAL SERVER ERROR] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:23 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137242929] + X-Android-Response-Source:[NETWORK 500] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242334] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9zbFduStgbkjq7wAg] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[failure] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Command,query +setRequestProperty:Content-Length,0 +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:200 +getHeaderFields: + null:[HTTP/1.1 200 OK] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:24 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137243529] + X-Android-Response-Source:[NETWORK 200] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242953] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9TPO7SRtgaHrYKAAQ] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[success] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Offset,0 +setRequestProperty:X-Goog-Upload-Command,upload +setDoOutput:true +setRequestProperty:Content-Length,262144 +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:500 +getHeaderFields: + null:[HTTP/1.1 500 INTERNAL SERVER ERROR] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:23 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137242929] + X-Android-Response-Source:[NETWORK 500] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242334] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9zbFduStgbkjq7wAg] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[failure] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Command,query +setRequestProperty:Content-Length,0 +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:200 +getHeaderFields: + null:[HTTP/1.1 200 OK] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:24 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137243529] + X-Android-Response-Source:[NETWORK 200] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242953] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9TPO7SRtgaHrYKAAQ] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[success] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Offset,0 +setRequestProperty:X-Goog-Upload-Command,upload +setDoOutput:true +setRequestProperty:Content-Length,262144 +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:500 +getHeaderFields: + null:[HTTP/1.1 500 INTERNAL SERVER ERROR] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:23 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137242929] + X-Android-Response-Source:[NETWORK 500] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242334] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9zbFduStgbkjq7wAg] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[failure] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Command,query +setRequestProperty:Content-Length,0 +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:200 +getHeaderFields: + null:[HTTP/1.1 200 OK] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:24 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137243529] + X-Android-Response-Source:[NETWORK 200] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242953] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9TPO7SRtgaHrYKAAQ] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[success] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Offset,0 +setRequestProperty:X-Goog-Upload-Command,upload +setDoOutput:true +setRequestProperty:Content-Length,262144 +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:500 +getHeaderFields: + null:[HTTP/1.1 500 INTERNAL SERVER ERROR] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:23 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137242929] + X-Android-Response-Source:[NETWORK 500] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242334] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9zbFduStgbkjq7wAg] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[failure] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Command,query +setRequestProperty:Content-Length,0 +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:200 +getHeaderFields: + null:[HTTP/1.1 200 OK] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:24 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137243529] + X-Android-Response-Source:[NETWORK 200] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242953] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9TPO7SRtgaHrYKAAQ] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[success] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Offset,0 +setRequestProperty:X-Goog-Upload-Command,upload +setDoOutput:true +setRequestProperty:Content-Length,262144 +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:500 +getHeaderFields: + null:[HTTP/1.1 500 INTERNAL SERVER ERROR] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:23 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137242929] + X-Android-Response-Source:[NETWORK 500] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242334] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9zbFduStgbkjq7wAg] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[failure] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Command,query +setRequestProperty:Content-Length,0 +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:200 +getHeaderFields: + null:[HTTP/1.1 200 OK] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:24 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137243529] + X-Android-Response-Source:[NETWORK 200] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242953] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9TPO7SRtgaHrYKAAQ] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[success] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Offset,0 +setRequestProperty:X-Goog-Upload-Command,upload +setDoOutput:true +setRequestProperty:Content-Length,262144 +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:500 +getHeaderFields: + null:[HTTP/1.1 500 INTERNAL SERVER ERROR] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:23 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137242929] + X-Android-Response-Source:[NETWORK 500] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242334] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9zbFduStgbkjq7wAg] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[failure] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Command,query +setRequestProperty:Content-Length,0 +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:200 +getHeaderFields: + null:[HTTP/1.1 200 OK] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:24 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137243529] + X-Android-Response-Source:[NETWORK 200] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242953] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9TPO7SRtgaHrYKAAQ] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[success] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Offset,0 +setRequestProperty:X-Goog-Upload-Command,upload +setDoOutput:true +setRequestProperty:Content-Length,262144 +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:500 +getHeaderFields: + null:[HTTP/1.1 500 INTERNAL SERVER ERROR] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:23 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137242929] + X-Android-Response-Source:[NETWORK 500] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242334] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9zbFduStgbkjq7wAg] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[failure] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Command,query +setRequestProperty:Content-Length,0 +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:200 +getHeaderFields: + null:[HTTP/1.1 200 OK] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:24 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137243529] + X-Android-Response-Source:[NETWORK 200] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242953] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9TPO7SRtgaHrYKAAQ] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/880] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[success] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: + +Url:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable +setRequestMethod:POST +setRequestProperty:X-Firebase-Storage-Version,Android/[No Gmscore] +setRequestProperty:x-firebase-gmpid,fooey +setRequestProperty:x-firebase-appcheck,eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ== +setRequestProperty:X-Goog-Upload-Protocol,resumable +setRequestProperty:X-Goog-Upload-Offset,0 +setRequestProperty:X-Goog-Upload-Command,upload +setDoOutput:true +setRequestProperty:Content-Length,262144 +setUseCaches:false +setDoInput:true +getOutputStream: +getResponseCode:500 +getHeaderFields: + null:[HTTP/1.1 500 INTERNAL SERVER ERROR] + Alt-Svc:[quic=":443"; ma=2592000; v="36,35,34,33,32"] + Content-Length:[0] + Content-Type:[text/html; charset=UTF-8] + Date:[Mon, 10 Oct 2016 22:07:23 GMT] + Server:[UploadServer] + X-Android-Received-Millis:[1476137242929] + X-Android-Response-Source:[NETWORK 500] + X-Android-Selected-Protocol:[http/1.1] + X-Android-Sent-Millis:[1476137242334] + X-Goog-Upload-Status:[active] + X-Google-Backends:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-DOS-Service-Trace:[main:apps-upload-embargo] + X-Google-GFE-Backend-Request-Info:[eid=GxH8V9zbFduStgbkjq7wAg] + X-Google-GFE-Request-Trace:[acsfoc19:443,/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927,acsfoc19:443] + X-Google-GFE-Response-Code-Details-Trace:[response_code_set_by_backend] + X-Google-GFE-Service-Trace:[apps-upload-embargo] + X-Google-Netmon-Label:[/bns/ph/borg/ph/bns/apps-upload/apps-upload.uploader/927] + X-Google-Service:[apps-upload-embargo] + X-Google-Shellfish-Status:[CIgCQEY] + X-GUploader-Customer:[firebase-storage] + X-GUploader-Request-Result:[failure] + X-GUploader-UploadID:[AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg] +getInputStream: +disconnect: diff --git a/firebase-storage/src/test/resources/activitylogs/fileUploadWith500_task.txt b/firebase-storage/src/test/resources/activitylogs/fileUploadWith500_task.txt new file mode 100644 index 00000000000..063ec876dcc --- /dev/null +++ b/firebase-storage/src/test/resources/activitylogs/fileUploadWith500_task.txt @@ -0,0 +1,68 @@ + +onProgress: + exceptionMessage: + targetStorageString:gs://fooey.appspot.com/image.jpg + bytesUploaded:0 + currentState:2 + uploadUri: + total bytes:1076408 +onProgress: + exceptionMessage: + targetStorageString:gs://fooey.appspot.com/image.jpg + bytesUploaded:0 + currentState:4 + uploadUri: + total bytes:1076408 +onProgress: + exceptionMessage: + targetStorageString:gs://fooey.appspot.com/image.jpg + bytesUploaded:0 + currentState:4 + uploadUri:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable + total bytes:1076408 +onProgress: + exceptionMessage: + targetStorageString:gs://fooey.appspot.com/image.jpg + bytesUploaded:0 + currentState:4 + uploadUri:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable + total bytes:1076408 +onProgress: + exceptionMessage: + targetStorageString:gs://fooey.appspot.com/image.jpg + bytesUploaded:0 + currentState:4 + uploadUri:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable + total bytes:1076408 +onProgress: + exceptionMessage: + targetStorageString:gs://fooey.appspot.com/image.jpg + bytesUploaded:0 + currentState:4 + uploadUri:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable + total bytes:1076408 +onProgress: + exceptionMessage: + targetStorageString:gs://fooey.appspot.com/image.jpg + bytesUploaded:0 + currentState:4 + uploadUri:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable + total bytes:1076408 +onProgress: + exceptionMessage: + targetStorageString:gs://fooey.appspot.com/image.jpg + bytesUploaded:0 + currentState:4 + uploadUri:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable + total bytes:1076408 +onProgress: + exceptionMessage: + targetStorageString:gs://fooey.appspot.com/image.jpg + bytesUploaded:0 + currentState:4 + uploadUri:https://firebasestorage.googleapis.com/v0/b/fooey.appspot.com/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2Uq98TD5-fHipJMqNua3J76QCFnDacqBbwpZJjpAVHWATgGP4sXS4zu2wBu-h4KKn2-jGDchzM59eFRVlqIN-PF5mtmNdg&upload_protocol=resumable + total bytes:1076408 +onFailure: +com.google.firebase.storage.StorageException: The operation retry limit has been exceeded. +onComplete:Success= +false \ No newline at end of file diff --git a/firebase-storage/src/testUtil/java/com/google/firebase/storage/TestDownloadHelper.java b/firebase-storage/src/testUtil/java/com/google/firebase/storage/TestDownloadHelper.java index 6fa0faf126a..10607e01af5 100644 --- a/firebase-storage/src/testUtil/java/com/google/firebase/storage/TestDownloadHelper.java +++ b/firebase-storage/src/testUtil/java/com/google/firebase/storage/TestDownloadHelper.java @@ -266,15 +266,15 @@ private static void verifyTaskCount(StorageReference reference, int expectedTask List globalDownloadTasks = reference.getActiveDownloadTasks(); Preconditions.checkState( globalDownloadTasks.size() == expectedTasks, - "Expected active download task to contain %s item(s), but contained %s item(s)", + "Expected active download task to contain %d item(s), but contained %d item(s)", globalDownloadTasks.size(), expectedTasks); List downloadTasksAtParent = StorageTaskManager.getInstance().getDownloadTasksUnder(reference.getParent()); Preconditions.checkState( downloadTasksAtParent.size() == expectedTasks, - "Expected active download task at location %s to contain %s item(s), " - + "but contained %s item(s)", + "Expected active download task at location %s to contain %d item(s), " + + "but contained %d item(s)", reference.getParent(), downloadTasksAtParent.size(), expectedTasks); diff --git a/firebase-storage/src/testUtil/java/com/google/firebase/storage/TestUploadHelper.java b/firebase-storage/src/testUtil/java/com/google/firebase/storage/TestUploadHelper.java index dc01718cca8..bd6b3050e9c 100644 --- a/firebase-storage/src/testUtil/java/com/google/firebase/storage/TestUploadHelper.java +++ b/firebase-storage/src/testUtil/java/com/google/firebase/storage/TestUploadHelper.java @@ -557,7 +557,7 @@ public static Task adaptiveChunking() { final ByteArrayInputStream inputStream = new ByteArrayInputStream(data); // This test will upload 2 MB of data: - // - it will read and upload one chunk of 256KB (258KB read, 258KB uploaded) + // - it will read and upload one chunk of 256KB (256KB read, 256KB uploaded) // - it will read and upload one chunk of 512KB (768KB read, 768KB uploaded) // - it will read and fail the upload one chunk of 1MB (1.75MB read, 768KB uploaded) // - it will upload 256KB from its local cache (1.75MB read, 1MB uploaded) @@ -686,7 +686,8 @@ private static void verifyTaskCount(StorageReference reference, int expectedTask List globalUploadTasks = reference.getActiveUploadTasks(); Preconditions.checkState( globalUploadTasks.size() == expectedTasks, - "Expected active upload task to contain %s item(s), but contained %s item(s)", + "Expected active upload task to contain %d item(s), but contained %d item(s)", + expectedTasks, globalUploadTasks.size()); List uploadTasksAtParent = StorageTaskManager.getInstance().getUploadTasksUnder(reference.getParent()); diff --git a/health-metrics/README.md b/health-metrics/README.md index bd8cb53a40c..b390ec2e938 100644 --- a/health-metrics/README.md +++ b/health-metrics/README.md @@ -12,4 +12,14 @@ Refer to [README.md](apk-size/README.md) in the subdirectory `apk-size` for more ## App startup time -**TODO(yifany)**: Add more details once the measurement tools and infrastructure is ready. +Firebase runs during different +[app lifecycle](https://d.android.com/guide/components/activities/process-lifecycle) +phases, and contributes to the overall +[app startup time](https://d.android.com/topic/performance/vitals/launch-time) +in many ways. + +We are currently using +[benchmarking](https://d.android.com/topic/performance/benchmarking/benchmarking-overview) +and [tracing](https://d.android.com/topic/performance/tracing) to measure its +latency impact. Refer to [README.md](benchmark/README.md) in the subdirectory +`benchmark` for more details. diff --git a/health-metrics/benchmark/README.md b/health-metrics/benchmark/README.md new file mode 100644 index 00000000000..5cffaf1532a --- /dev/null +++ b/health-metrics/benchmark/README.md @@ -0,0 +1,112 @@ +# Benchmark + +This directory contains the benchmark test apps used for measuring latency for +initializing Firebase Android SDKs during app startup. + +## Test app configurations + +[config.yaml](config.yaml) contains a list of configuration blocks for +building a macrobenchmark test app for each of the Firebase Android SDKs. +If not all of them are required, comment out irrelevant ones for faster build +and test time. + +## Run benchmark tests + +### Prerequisite + +1. `fireci` CLI tool + + Refer to its [readme](../../ci/fireci/README.md) for how to install it. + +1. `google-services.json` + + Download it from the Firebase project + [`fireescape-integ-tests`](https://firebase.corp.google.com/u/0/project/fireescape-integ-tests) + to the directory `./template/app`. + +1. Authentication to Google Cloud + + Authentication is required by Google Cloud SDK and Google Cloud Storage + client library used in the benchmark tests. + + One simple way is to configure it is to set an environment variable + `GOOGLE_APPLICATION_CREDENTIALS` to a service account key file. However, + please refer to the official Google Cloud + [doc](https://cloud.google.com/docs/authentication) for full guidance on + authentication. + +### Run benchmark tests locally + +1. Build all test apps by running below command in the root + directory `firebase-android-sdk`: + + ```shell + fireci macrobenchmark --build-only + ``` + +1. [Connect an Android device to the computer](https://d.android.com/studio/run/device) + +1. Locate the temporary test apps directory from the log, for example: + + - on linux: `/tmp/benchmark-test-*/` + - on macos: `/var/folders/**/benchmark-test-*/` + +1. Start the benchmark tests from CLI or Android Studio: + + - CLI + + Run below command in the above test app project directory + + ``` + ./gradlew :macrobenchmark:connectedCheck + ``` + + - Android Studio + + 1. Import the project (e.g. `**/benchmark-test-*/firestore`) into Android Studio + 1. Start the benchmark test by clicking gutter icons in the file `BenchmarkTest.kt` + +1. Inspect the benchmark test results: + + - CLI + + Result files are created in `/macrobenchmark/build/outputs/`: + + - `*-benchmarkData.json` contains metric aggregates + - `*.perfetto-trace` are the raw trace files + + Additionally, upload `.perfetto-trace` files to + [Perfetto Trace Viewer](https://ui.perfetto.dev/) to visualize all traces. + + - Android Studio + + Test results are displayed directly in the "Run" tool window, including + + - macrobenchmark built-in metrics + - duration of custom traces + - links to trace files that can be visualized within the IDE + + Alternatively, same set of result files are produced at the same output + location as invoking tests from CLI, which can be used for inspection. + +### Run benchmark tests on Firebase Test Lab + +Build and run all tests on FTL by running below command in the root +directory `firebase-android-sdk`: + +``` +fireci macrobenchmark +``` + +Alternatively, it is possible to build all test apps via steps described in +[Running benchmark tests locally](#running-benchmark-tests-locally) +and manually +[run tests on FTL with `gcloud` CLI ](https://firebase.google.com/docs/test-lab/android/command-line#running_your_instrumentation_tests). + +Aggregated benchmark results are displayed in the log. The log also +contains links to FTL result pages and result files on Google Cloud Storage. + +## Toolchains + +- Gradle 7.5.1 +- Android Gradle Plugin 7.2.2 diff --git a/health-metrics/benchmark/config.yaml b/health-metrics/benchmark/config.yaml new file mode 100644 index 00000000000..8852965302e --- /dev/null +++ b/health-metrics/benchmark/config.yaml @@ -0,0 +1,72 @@ +# Configurations for tracing test apps construction. +# +# Note: +# - One SDK may contain multiple test apps +# - Common plugins and traces are applied to all test apps during runtime +# - Test apps can also define their additional gradle plugins and custom traces, e.g. +# +# test-apps: +# - sdk: firebase-crashlytics +# name: crashlytics-1 +# plugins: [com.google.firebase.] +# traces: [crashlytics-custom-trace] +# +# - sdk: firebase-crashlytics +# name: crashlytics-2 +# ...... +# + +common-plugins: [com.google.gms.google-services] + +common-traces: [Firebase, ComponentDiscovery, Runtime] + +test-apps: + - sdk: firebase-config + name: config + dependencies: [com.google.firebase:firebase-config-ktx] + - sdk: firebase-common + name: common + dependencies: [com.google.firebase:firebase-common] + - sdk: firebase-crashlytics + name: crash + dependencies: [com.google.firebase:firebase-crashlytics-ktx] + plugins: [com.google.firebase.crashlytics] + - sdk: firebase-database + name: database + dependencies: [com.google.firebase:firebase-database-ktx] + - sdk: firebase-dynamic-links + name: fdl + dependencies: [com.google.firebase:firebase-dynamic-links-ktx] + - sdk: firebase-firestore + name: firestore + dependencies: [com.google.firebase:firebase-firestore-ktx] + - sdk: firebase-functions + name: functions + dependencies: [com.google.firebase:firebase-functions-ktx] + # TODO(yifany): disable temporarily due to errors of duplicate class and gradle crash + # - sdk: firebase-inappmessaging-display + # name: fiam + # dependencies: + # - com.google.firebase:firebase-analytics-ktx@18.0.3 + # - com.google.firebase:firebase-inappmessaging-ktx + # - com.google.firebase:firebase-inappmessaging-display-ktx + - sdk: firebase-messaging + name: message + dependencies: [com.google.firebase:firebase-messaging-ktx] + - sdk: firebase-perf + name: perf + dependencies: [com.google.firebase:firebase-perf-ktx] + plugins: [com.google.firebase.firebase-perf] + - sdk: firebase-storage + name: stroage + dependencies: [com.google.firebase:firebase-storage-ktx] + + +# TODO(yifany): google3 sdks, customizing FTL devices +# auth +# analytics +# combined +# - crashlytics + analytics +# - crashlytics + fireperf +# - auth + firestore +# - ... diff --git a/health-metrics/macrobenchmark/template/app/build.gradle.mustache b/health-metrics/benchmark/template/app/build.gradle.mustache similarity index 76% rename from health-metrics/macrobenchmark/template/app/build.gradle.mustache rename to health-metrics/benchmark/template/app/build.gradle.mustache index 73537a6300b..5dbc037af99 100644 --- a/health-metrics/macrobenchmark/template/app/build.gradle.mustache +++ b/health-metrics/benchmark/template/app/build.gradle.mustache @@ -14,28 +14,28 @@ plugins { id 'com.android.application' - id 'kotlin-android' + id 'org.jetbrains.kotlin.android' {{#plugins}} id '{{.}}' {{/plugins}} } android { - compileSdkVersion 30 - buildToolsVersion '30.0.3' + compileSdkVersion 32 defaultConfig { - applicationId 'com.google.firebase.macrobenchmark' + applicationId 'com.google.firebase.benchmark' minSdkVersion 29 - targetSdkVersion 30 + targetSdkVersion 32 versionCode 1 - versionName "1.0" + versionName '1.0' testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } buildTypes { - release { + benchmark { + debuggable false minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' @@ -64,12 +64,13 @@ dependencies { implementation '{{key}}:{{version}}' {{/dependencies}} - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'androidx.core:core-ktx:1.5.0' - implementation 'androidx.appcompat:appcompat:1.3.0' - implementation 'com.google.android.material:material:1.3.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.tracing:tracing-ktx:1.1.0' + + implementation 'androidx.core:core-ktx:1.8.0' + implementation 'androidx.appcompat:appcompat:1.5.0' + implementation 'com.google.android.material:material:1.6.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' } diff --git a/health-metrics/macrobenchmark/template/app/proguard-rules.pro b/health-metrics/benchmark/template/app/proguard-rules.pro similarity index 100% rename from health-metrics/macrobenchmark/template/app/proguard-rules.pro rename to health-metrics/benchmark/template/app/proguard-rules.pro diff --git a/health-metrics/benchmark/template/app/src/main/AndroidManifest.xml b/health-metrics/benchmark/template/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..400075eb9c4 --- /dev/null +++ b/health-metrics/benchmark/template/app/src/main/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + diff --git a/health-metrics/macrobenchmark/template/app/src/main/java/com/google/firebase/benchmark/MainActivity.kt b/health-metrics/benchmark/template/app/src/main/java/com/google/firebase/benchmark/MainActivity.kt similarity index 100% rename from health-metrics/macrobenchmark/template/app/src/main/java/com/google/firebase/benchmark/MainActivity.kt rename to health-metrics/benchmark/template/app/src/main/java/com/google/firebase/benchmark/MainActivity.kt diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/health-metrics/benchmark/template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 99% rename from health-metrics/macrobenchmark/template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to health-metrics/benchmark/template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml index 2b068d11462..7706ab9e6d4 100644 --- a/health-metrics/macrobenchmark/template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ b/health-metrics/benchmark/template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -27,4 +27,4 @@ android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z" android:strokeWidth="1" android:strokeColor="#00000000" /> - \ No newline at end of file + diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/drawable/ic_launcher_background.xml b/health-metrics/benchmark/template/app/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from health-metrics/macrobenchmark/template/app/src/main/res/drawable/ic_launcher_background.xml rename to health-metrics/benchmark/template/app/src/main/res/drawable/ic_launcher_background.xml diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/layout/activity_main.xml b/health-metrics/benchmark/template/app/src/main/res/layout/activity_main.xml similarity index 79% rename from health-metrics/macrobenchmark/template/app/src/main/res/layout/activity_main.xml rename to health-metrics/benchmark/template/app/src/main/res/layout/activity_main.xml index 4fc244418b5..c75d0576c09 100644 --- a/health-metrics/macrobenchmark/template/app/src/main/res/layout/activity_main.xml +++ b/health-metrics/benchmark/template/app/src/main/res/layout/activity_main.xml @@ -11,8 +11,8 @@ android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintRight_toRightOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - \ No newline at end of file + diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/health-metrics/benchmark/template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 93% rename from health-metrics/macrobenchmark/template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to health-metrics/benchmark/template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index eca70cfe52e..6b78462d615 100644 --- a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/health-metrics/benchmark/template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/health-metrics/benchmark/template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 93% rename from health-metrics/macrobenchmark/template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to health-metrics/benchmark/template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index eca70cfe52e..6b78462d615 100644 --- a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/health-metrics/benchmark/template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/health-metrics/benchmark/template/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/health-metrics/benchmark/template/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 00000000000..c209e78ecd3 Binary files /dev/null and b/health-metrics/benchmark/template/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/health-metrics/benchmark/template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/health-metrics/benchmark/template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 00000000000..b2dfe3d1ba5 Binary files /dev/null and b/health-metrics/benchmark/template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/health-metrics/benchmark/template/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/health-metrics/benchmark/template/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 00000000000..4f0f1d64e58 Binary files /dev/null and b/health-metrics/benchmark/template/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/health-metrics/benchmark/template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/health-metrics/benchmark/template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 00000000000..62b611da081 Binary files /dev/null and b/health-metrics/benchmark/template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/health-metrics/benchmark/template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/health-metrics/benchmark/template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 00000000000..948a3070fe3 Binary files /dev/null and b/health-metrics/benchmark/template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/health-metrics/benchmark/template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/health-metrics/benchmark/template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 00000000000..1b9a6956b3a Binary files /dev/null and b/health-metrics/benchmark/template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/health-metrics/benchmark/template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/health-metrics/benchmark/template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 00000000000..28d4b77f9f0 Binary files /dev/null and b/health-metrics/benchmark/template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/health-metrics/benchmark/template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/health-metrics/benchmark/template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 00000000000..9287f508362 Binary files /dev/null and b/health-metrics/benchmark/template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/health-metrics/benchmark/template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/health-metrics/benchmark/template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 00000000000..aa7d6427e6f Binary files /dev/null and b/health-metrics/benchmark/template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/health-metrics/benchmark/template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/health-metrics/benchmark/template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 00000000000..9126ae37cbc Binary files /dev/null and b/health-metrics/benchmark/template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/values-night/themes.xml b/health-metrics/benchmark/template/app/src/main/res/values-night/themes.xml similarity index 86% rename from health-metrics/macrobenchmark/template/app/src/main/res/values-night/themes.xml rename to health-metrics/benchmark/template/app/src/main/res/values-night/themes.xml index 88f1c721163..78ada11fae6 100644 --- a/health-metrics/macrobenchmark/template/app/src/main/res/values-night/themes.xml +++ b/health-metrics/benchmark/template/app/src/main/res/values-night/themes.xml @@ -1,6 +1,6 @@ - - \ No newline at end of file + diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/values/colors.xml b/health-metrics/benchmark/template/app/src/main/res/values/colors.xml similarity index 96% rename from health-metrics/macrobenchmark/template/app/src/main/res/values/colors.xml rename to health-metrics/benchmark/template/app/src/main/res/values/colors.xml index f8c6127d327..ca1931bca99 100644 --- a/health-metrics/macrobenchmark/template/app/src/main/res/values/colors.xml +++ b/health-metrics/benchmark/template/app/src/main/res/values/colors.xml @@ -7,4 +7,4 @@ #FF018786 #FF000000 #FFFFFFFF - \ No newline at end of file + diff --git a/health-metrics/benchmark/template/app/src/main/res/values/strings.xml b/health-metrics/benchmark/template/app/src/main/res/values/strings.xml new file mode 100644 index 00000000000..2acaa64f542 --- /dev/null +++ b/health-metrics/benchmark/template/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + benchmark + diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/values/themes.xml b/health-metrics/benchmark/template/app/src/main/res/values/themes.xml similarity index 86% rename from health-metrics/macrobenchmark/template/app/src/main/res/values/themes.xml rename to health-metrics/benchmark/template/app/src/main/res/values/themes.xml index 2bbfc467c2c..11866afe933 100644 --- a/health-metrics/macrobenchmark/template/app/src/main/res/values/themes.xml +++ b/health-metrics/benchmark/template/app/src/main/res/values/themes.xml @@ -1,6 +1,6 @@ - - \ No newline at end of file + diff --git a/health-metrics/benchmark/template/app/src/main/res/xml/backup_rules.xml b/health-metrics/benchmark/template/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 00000000000..148c18b6593 --- /dev/null +++ b/health-metrics/benchmark/template/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + diff --git a/health-metrics/benchmark/template/app/src/main/res/xml/data_extraction_rules.xml b/health-metrics/benchmark/template/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 00000000000..0c4f95cab91 --- /dev/null +++ b/health-metrics/benchmark/template/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/health-metrics/benchmark/template/build.gradle b/health-metrics/benchmark/template/build.gradle new file mode 100644 index 00000000000..a83d229b243 --- /dev/null +++ b/health-metrics/benchmark/template/build.gradle @@ -0,0 +1,28 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +plugins { + id 'com.android.application' version '7.2.2' apply false + id 'com.android.library' version '7.2.2' apply false + id 'com.android.test' version '7.2.2' apply false + id 'org.jetbrains.kotlin.android' version '1.7.10' apply false + + id 'com.google.gms.google-services' version '4.3.13' apply false + id 'com.google.firebase.crashlytics' version '2.9.1' apply false + id 'com.google.firebase.firebase-perf' version '1.4.1' apply false +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/health-metrics/macrobenchmark/template/gradle.properties b/health-metrics/benchmark/template/gradle.properties similarity index 96% rename from health-metrics/macrobenchmark/template/gradle.properties rename to health-metrics/benchmark/template/gradle.properties index a7d19a63475..a90756bf7d4 100644 --- a/health-metrics/macrobenchmark/template/gradle.properties +++ b/health-metrics/benchmark/template/gradle.properties @@ -20,7 +20,7 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx512m -Xms256m -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Xmx1024m -Xms512m -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects diff --git a/health-metrics/macrobenchmark/template/benchmark/build.gradle b/health-metrics/benchmark/template/macrobenchmark/build.gradle similarity index 52% rename from health-metrics/macrobenchmark/template/benchmark/build.gradle rename to health-metrics/benchmark/template/macrobenchmark/build.gradle index aacb27f8539..be80bc79f06 100644 --- a/health-metrics/macrobenchmark/template/benchmark/build.gradle +++ b/health-metrics/benchmark/template/macrobenchmark/build.gradle @@ -13,48 +13,50 @@ // limitations under the License. plugins { - id 'com.android.library' - id 'kotlin-android' + id 'com.android.test' + id 'org.jetbrains.kotlin.android' } android { - compileSdkVersion 30 - buildToolsVersion '30.0.3' + compileSdkVersion 32 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } defaultConfig { - minSdkVersion 29 - targetSdkVersion 30 - versionCode 1 - versionName '1.0' + minSdk 29 + targetSdk 32 testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + benchmark { + debuggable = true + signingConfig = debug.signingConfig + matchingFallbacks = ["release"] } } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = '1.8' - } + targetProjectPath = ":app" + experimentalProperties["android.experimental.self-instrumenting"] = true } dependencies { - androidTestImplementation 'androidx.benchmark:benchmark-macro-junit4:1.1.0-alpha02' - - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'androidx.core:core-ktx:1.5.0' - implementation 'androidx.appcompat:appcompat:1.3.0' - implementation 'com.google.android.material:material:1.3.0' - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + implementation 'androidx.test.ext:junit:1.1.3' + implementation 'androidx.test.espresso:espresso-core:3.4.0' + implementation 'androidx.test.uiautomator:uiautomator:2.2.0' + implementation 'androidx.benchmark:benchmark-macro-junit4:1.1.0' +} + +androidComponents { + beforeVariants(selector().all()) { + enabled = buildType == "benchmark" + } } diff --git a/health-metrics/macrobenchmark/template/benchmark/proguard-rules.pro b/health-metrics/benchmark/template/macrobenchmark/proguard-rules.pro similarity index 100% rename from health-metrics/macrobenchmark/template/benchmark/proguard-rules.pro rename to health-metrics/benchmark/template/macrobenchmark/proguard-rules.pro diff --git a/health-metrics/benchmark/template/macrobenchmark/src/main/AndroidManifest.xml b/health-metrics/benchmark/template/macrobenchmark/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..5b21eea1a7f --- /dev/null +++ b/health-metrics/benchmark/template/macrobenchmark/src/main/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/health-metrics/benchmark/template/macrobenchmark/src/main/java/com/google/firebase/macrobenchmark/BenchmarkTest.kt.mustache b/health-metrics/benchmark/template/macrobenchmark/src/main/java/com/google/firebase/macrobenchmark/BenchmarkTest.kt.mustache new file mode 100644 index 00000000000..4fa5af3546e --- /dev/null +++ b/health-metrics/benchmark/template/macrobenchmark/src/main/java/com/google/firebase/macrobenchmark/BenchmarkTest.kt.mustache @@ -0,0 +1,48 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.macrobenchmark + +import androidx.benchmark.macro.ExperimentalMetricApi +import androidx.benchmark.macro.StartupMode +import androidx.benchmark.macro.StartupTimingMetric +import androidx.benchmark.macro.TraceSectionMetric +import androidx.benchmark.macro.junit4.MacrobenchmarkRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class StartupBenchmark { + @get:Rule + val benchmarkRule = MacrobenchmarkRule() + + @OptIn(ExperimentalMetricApi::class) + @Test + fun startup() = benchmarkRule.measureRepeated( + packageName = "com.google.firebase.benchmark", + metrics = listOf( + StartupTimingMetric(), + {{#traces}} + TraceSectionMetric("{{.}}"), + {{/traces}} + ), + iterations = 5, + startupMode = StartupMode.COLD + ) { + pressHome() + startActivityAndWait() + } +} diff --git a/health-metrics/macrobenchmark/template/settings.gradle b/health-metrics/benchmark/template/settings.gradle.mustache similarity index 60% rename from health-metrics/macrobenchmark/template/settings.gradle rename to health-metrics/benchmark/template/settings.gradle.mustache index 3c1a05b94ef..2428ba1c912 100644 --- a/health-metrics/macrobenchmark/template/settings.gradle +++ b/health-metrics/benchmark/template/settings.gradle.mustache @@ -12,6 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. -rootProject.name = 'macrobenchmark' +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + + maven { + url '{{m2repository}}' + } + } +} + +rootProject.name = 'benchmark' include ':app' -include ':benchmark' +include ':macrobenchmark' diff --git a/health-metrics/macrobenchmark/config.yaml b/health-metrics/macrobenchmark/config.yaml deleted file mode 100644 index 791885dd9ef..00000000000 --- a/health-metrics/macrobenchmark/config.yaml +++ /dev/null @@ -1,74 +0,0 @@ -baseline: - name: baseline - -firebase-config: - name: config - dependencies: - - com.google.firebase:firebase-config-ktx - -firebase-common: - name: common - dependencies: - - com.google.firebase:firebase-common - -firebase-crashlytics: - name: crash - dependencies: - - com.google.firebase:firebase-crashlytics-ktx - plugins: - - com.google.firebase.crashlytics - -firebase-database: - name: database - dependencies: - - com.google.firebase:firebase-database-ktx - -firebase-dynamic-links: - name: dynamiclinks - dependencies: - - com.google.firebase:firebase-dynamic-links-ktx - -firebase-firestore: - name: firestore - dependencies: - - com.google.firebase:firebase-firestore-ktx - -firebase-functions: - name: functions - dependencies: - - com.google.firebase:firebase-functions-ktx - -firebase-inappmessaging-display: - name: inappmessaging - dependencies: - - com.google.firebase:firebase-analytics-ktx@18.0.3 - - com.google.firebase:firebase-inappmessaging-ktx - - com.google.firebase:firebase-inappmessaging-display-ktx - -firebase-messaging: - name: messaging - dependencies: - - com.google.firebase:firebase-messaging-ktx - -firebase-perf: - name: perf - dependencies: - - com.google.firebase:firebase-perf-ktx - plugins: - - com.google.firebase.firebase-perf - -firebase-storage: - name: storage - dependencies: - - com.google.firebase:firebase-storage-ktx - - - -# TODO(yifany): google3 sdks, customizing FTL devices -# auth -# analytics -# combined -# - crashlytics + analytics -# - crashlytics + fireperf -# - auth + firestore -# - ... diff --git a/health-metrics/macrobenchmark/template/app/src/main/AndroidManifest.xml b/health-metrics/macrobenchmark/template/app/src/main/AndroidManifest.xml deleted file mode 100644 index 4920e1c389e..00000000000 --- a/health-metrics/macrobenchmark/template/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-hdpi/ic_launcher.png b/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index a571e60098c..00000000000 Binary files a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index 61da551c559..00000000000 Binary files a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-mdpi/ic_launcher.png b/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index c41dd285319..00000000000 Binary files a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-mdpi/ic_launcher_round.png deleted file mode 100644 index db5080a7527..00000000000 Binary files a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 6dba46dab19..00000000000 Binary files a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100644 index da31a871c8d..00000000000 Binary files a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 15ac681720f..00000000000 Binary files a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png deleted file mode 100644 index b216f2d313c..00000000000 Binary files a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index f25a4197447..00000000000 Binary files a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100644 index e96783ccce8..00000000000 Binary files a/health-metrics/macrobenchmark/template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/health-metrics/macrobenchmark/template/app/src/main/res/values/strings.xml b/health-metrics/macrobenchmark/template/app/src/main/res/values/strings.xml deleted file mode 100644 index 84d56e22541..00000000000 --- a/health-metrics/macrobenchmark/template/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - macrobenchmark - \ No newline at end of file diff --git a/health-metrics/macrobenchmark/template/benchmark/src/androidTest/java/com/google/firebase/benchmark/BenchmarkTest.kt.mustache b/health-metrics/macrobenchmark/template/benchmark/src/androidTest/java/com/google/firebase/benchmark/BenchmarkTest.kt.mustache deleted file mode 100644 index 5b35820fe9b..00000000000 --- a/health-metrics/macrobenchmark/template/benchmark/src/androidTest/java/com/google/firebase/benchmark/BenchmarkTest.kt.mustache +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2021 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.google.firebase.benchmark - -import android.content.Intent -import androidx.benchmark.macro.StartupMode -import androidx.benchmark.macro.StartupTimingMetric -import androidx.benchmark.macro.junit4.MacrobenchmarkRule -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.Parameterized - - -@RunWith(Parameterized::class) -class BenchmarkTest(private val startupMode: StartupMode) { - @get:Rule - val benchmarkRule = MacrobenchmarkRule() - - @Test - fun startup() = benchmarkRule.measureRepeated( - packageName = "com.google.firebase.macrobenchmark", - metrics = listOf(StartupTimingMetric()), - iterations = 20, - startupMode = startupMode - ) { - pressHome() - val intent = Intent() - intent.setPackage("com.google.firebase.macrobenchmark") - intent.setAction("com.google.firebase.benchmark.STARTUP_ACTIVITY") - startActivityAndWait(intent) - } - - companion object { - @Parameterized.Parameters(name = "mode={0}") - @JvmStatic - fun parameters(): List> { - return listOf(StartupMode.COLD, StartupMode.WARM, StartupMode.HOT) - .map { arrayOf(it) } - } - } -} diff --git a/health-metrics/macrobenchmark/template/build.gradle b/health-metrics/macrobenchmark/template/build.gradle deleted file mode 100644 index ba1e309c38a..00000000000 --- a/health-metrics/macrobenchmark/template/build.gradle +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2021 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -buildscript { - ext.kotlin_version = "1.5.0" - repositories { - google() - mavenCentral() - } - dependencies { - classpath "com.android.tools.build:gradle:4.2.0" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - classpath 'com.google.gms:google-services:4.3.5' - - // Add the Crashlytics Gradle plugin (be sure to add version - // 2.0.0 or later if you built your app with Android Studio 4.1). - classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.2' - - // Add the dependency for the Performance Monitoring plugin - classpath 'com.google.firebase:perf-plugin:1.3.5' // Performance Monitoring plugin - } -} - -allprojects { - repositories { - google() - mavenCentral() - - maven { - url rootProject.file('../../../../build/m2repository') - } - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/kotlindoc/package-lists/firebase/package-list b/kotlindoc/package-lists/firebase/package-list index 01fd19a663b..0b11ecaccf7 100644 --- a/kotlindoc/package-lists/firebase/package-list +++ b/kotlindoc/package-lists/firebase/package-list @@ -2,6 +2,7 @@ com.google.firebase com.google.firebase.analytics com.google.firebase.analytics.ktx com.google.firebase.appcheck +com.google.firebase.appcheck.ktx com.google.firebase.appcheck.debug com.google.firebase.appcheck.debug.testing com.google.firebase.appcheck.playintegrity diff --git a/smoke-tests/src/androidTest/backend/functions/functions/package-lock.json b/smoke-tests/src/androidTest/backend/functions/functions/package-lock.json index 34330778194..627b8b60ae9 100644 --- a/smoke-tests/src/androidTest/backend/functions/functions/package-lock.json +++ b/smoke-tests/src/androidTest/backend/functions/functions/package-lock.json @@ -4,6 +4,7 @@ "requires": true, "packages": { "": { + "name": "functions", "dependencies": { "firebase-admin": "^11.0.0", "firebase-functions": "^3.21.2" @@ -30,9 +31,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true, "engines": { "node": ">=6.9.0" @@ -93,6 +94,15 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -161,47 +171,47 @@ } }, "node_modules/@firebase/component": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.16.tgz", - "integrity": "sha512-/pkl77mN9PT7dTSzNu1CrvIvd+z1CdePnEl+VITaeSBs9Ko7ZVvSIlzQLbSwqksXX3bAHpxej0Mg6mVKQiRVSw==", + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.17.tgz", + "integrity": "sha512-mTM5CBSIlmI+i76qU4+DhuExnWtzcPS3cVgObA3VAjliPPr3GrUlTaaa8KBGfxsD27juQxMsYA0TvCR5X+GQ3Q==", "dependencies": { - "@firebase/util": "1.6.2", + "@firebase/util": "1.6.3", "tslib": "^2.1.0" } }, "node_modules/@firebase/database": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.13.2.tgz", - "integrity": "sha512-wKkBD4rq6PPv9gl1hNJNpl0R0bwJmXCJfDuvotjXmTcU7kV0AIaJ45GVhULkbSCApAAFC6QUJ91oasDUO1ZVxw==", + "version": "0.13.6", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.13.6.tgz", + "integrity": "sha512-5IZIBw2LT50Z8mwmKYmdX37p+Gg2HgeJsrruZmRyOSVgbfoY4Pg87n1uFx6qWqDmfL6HwQgwcrrQfVIXE3C5SA==", "dependencies": { "@firebase/auth-interop-types": "0.1.6", - "@firebase/component": "0.5.16", + "@firebase/component": "0.5.17", "@firebase/logger": "0.3.3", - "@firebase/util": "1.6.2", + "@firebase/util": "1.6.3", "faye-websocket": "0.11.4", "tslib": "^2.1.0" } }, "node_modules/@firebase/database-compat": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.2.2.tgz", - "integrity": "sha512-3wLHJ54WHMhrveCywCMbkspshFezN07PLOIsmqELM1+pmrg3bwMj9u/o3Equ0DwmESMnchp5sMxgzdBUOextJg==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.2.6.tgz", + "integrity": "sha512-Ls1BAODaiDYgeJljrIgSuC7JkFIY/HNhhNYebzZSoGQU62RuvnaO3Qgp2EH6h2LzHyRnycNadfh1suROtPaUIA==", "dependencies": { - "@firebase/component": "0.5.16", - "@firebase/database": "0.13.2", - "@firebase/database-types": "0.9.10", + "@firebase/component": "0.5.17", + "@firebase/database": "0.13.6", + "@firebase/database-types": "0.9.13", "@firebase/logger": "0.3.3", - "@firebase/util": "1.6.2", + "@firebase/util": "1.6.3", "tslib": "^2.1.0" } }, "node_modules/@firebase/database-types": { - "version": "0.9.10", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.9.10.tgz", - "integrity": "sha512-2ji6nXRRsY+7hgU6zRhUtK0RmSjVWM71taI7Flgaw+BnopCo/lDF5HSwxp8z7LtiHlvQqeRA3Ozqx5VhlAbiKg==", + "version": "0.9.13", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.9.13.tgz", + "integrity": "sha512-dIJ1zGe3EHMhwcvukTOPzYlFYFIG1Et5Znl7s7y/ZTN2/toARRNnsv1qCKvqevIMYKvIrRsYOYfOXDS8l1YIJA==", "dependencies": { "@firebase/app-types": "0.7.0", - "@firebase/util": "1.6.2" + "@firebase/util": "1.6.3" } }, "node_modules/@firebase/logger": { @@ -213,9 +223,9 @@ } }, "node_modules/@firebase/util": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.6.2.tgz", - "integrity": "sha512-VYDqEf/+mS7n0nPj6qJDJYFtKIEfOaTtQeNDsd3x+xp8HWvrbygWOexzeGicLP1dvEzrKr3eQGcJmmmYN3TIsA==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.6.3.tgz", + "integrity": "sha512-FujteO6Zjv6v8A4HS+t7c+PjU0Kaxj+rOnka0BsI/twUaCC9t8EQPmXpWZdk7XfszfahJn2pqsflUWUhtUkRlg==", "dependencies": { "tslib": "^2.1.0" } @@ -258,18 +268,18 @@ } }, "node_modules/@google-cloud/promisify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-3.0.0.tgz", - "integrity": "sha512-91ArYvRgXWb73YvEOBMmOcJc0bDRs5yiVHnqkwoG0f3nm7nZuipllz6e7BvFESBvjkDTBC0zMD8QxedUwNLc1A==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-3.0.1.tgz", + "integrity": "sha512-z1CjRjtQyBOYL+5Qr9DdYIfrdLBe746jRTYfaYU6MeXkqp7UfYs/jX16lFFVzZ7PGEJvqZNqYUEtb1mvDww4pA==", "optional": true, "engines": { "node": ">=12" } }, "node_modules/@google-cloud/storage": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.2.2.tgz", - "integrity": "sha512-KhAOxmGfmELKKn6cdvgGfAi/YBLi19hI1jX3QI7xQmbeajSFMgUKrIPbbyfMIxQPOEQ9vG0MQX1uganlA/HTRA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.5.0.tgz", + "integrity": "sha512-fAWk+NxsgII769YMfq/dDf3vaCuRWkp8aKmBZfi8NPTkKOm24tv8wqb4MQ0XL/I09oLiNqUZZe4q6hqzzQbryA==", "optional": true, "dependencies": { "@google-cloud/paginator": "^3.0.7", @@ -287,9 +297,7 @@ "mime": "^3.0.0", "mime-types": "^2.0.8", "p-limit": "^3.0.1", - "pumpify": "^2.0.0", "retry-request": "^5.0.0", - "stream-events": "^1.0.4", "teeny-request": "^8.0.0", "uuid": "^8.0.0" }, @@ -298,18 +306,67 @@ } }, "node_modules/@grpc/grpc-js": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.6.7.tgz", - "integrity": "sha512-eBM03pu9hd3VqDQG+kHahiG1x80RGkkqqRb1Pchcwqej/KkAH95gAvKs6laqaHCycYaPK+TKuNQnOz9UXYA8qw==", + "version": "1.6.12", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.6.12.tgz", + "integrity": "sha512-JmvQ03OTSpVd9JTlj/K3IWHSz4Gk/JMLUTtW7Zb0KvO1LcOYGATh5cNuRYzCAeDR3O8wq+q8FZe97eO9MBrkUw==", "optional": true, "dependencies": { - "@grpc/proto-loader": "^0.6.4", + "@grpc/proto-loader": "^0.7.0", "@types/node": ">=12.12.47" }, "engines": { "node": "^8.13.0 || >=10.10.0" } }, + "node_modules/@grpc/grpc-js/node_modules/@grpc/proto-loader": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.2.tgz", + "integrity": "sha512-jCdyLIT/tdQ1zhrbTQnJNK5nbDf0GoBpy5jVNywBzzMDF+Vs6uEaHnfz46dMtDxkvwrF2hzk5Z67goliceH0sA==", + "optional": true, + "dependencies": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^7.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/grpc-js/node_modules/protobufjs": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.1.tgz", + "integrity": "sha512-d0nMQqS/aT3lfV8bKi9Gbg73vPd2LcDdTDOu6RE/M+h9DY8g1EmDzk3ADPccthEWfTBjkR2oxNdx9Gs8YubT+g==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@grpc/grpc-js/node_modules/protobufjs/node_modules/long": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.0.tgz", + "integrity": "sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w==", + "optional": true + }, "node_modules/@grpc/proto-loader": { "version": "0.6.13", "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.13.tgz", @@ -443,9 +500,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.29", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz", - "integrity": "sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==", + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -453,17 +510,17 @@ } }, "node_modules/@types/jsonwebtoken": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.8.tgz", - "integrity": "sha512-zm6xBQpFDIDM6o9r6HSgDeIcLy82TKWctCXEPbJJcXb5AKmi5BNNdLXneixK4lplX3PqIVcwLBCGE/kAGnlD4A==", + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.9.tgz", + "integrity": "sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==", "dependencies": { "@types/node": "*" } }, "node_modules/@types/lodash": { - "version": "4.14.182", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", - "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==", + "version": "4.14.185", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.185.tgz", + "integrity": "sha512-evMDG1bC4rgQg4ku9tKpuMh5iBNEwNa3tf9zRHdP1qlv+1WUg44xat4IxCE14gIpZRGUUWAx2VhItCZc25NfMA==", "dev": true }, "node_modules/@types/long": { @@ -473,14 +530,14 @@ "optional": true }, "node_modules/@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, "node_modules/@types/node": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.1.tgz", - "integrity": "sha512-CmR8+Tsy95hhwtZBKJBs0/FFq4XX7sDZHlGGf+0q+BRZfMbOTkzkj0AFAuTyXbObDIoanaBBW0+KEW+m3N16Wg==" + "version": "18.7.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", + "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -493,11 +550,11 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "node_modules/@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", "dependencies": { - "@types/mime": "^1", + "@types/mime": "*", "@types/node": "*" } }, @@ -675,9 +732,9 @@ "optional": true }, "node_modules/bignumber.js": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", - "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.0.tgz", + "integrity": "sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A==", "optional": true, "engines": { "node": "*" @@ -1015,15 +1072,6 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/eslint": { "version": "7.19.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.19.0.tgz", @@ -1103,6 +1151,15 @@ "node": ">=8.0.0" } }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/eslint-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", @@ -1184,15 +1241,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -1205,7 +1253,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -1214,15 +1262,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -1328,9 +1367,9 @@ "dev": true }, "node_modules/fast-text-encoding": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.4.tgz", - "integrity": "sha512-x6lDDm/tBAzX9kmsPcZsNbvDs3Zey3+scsxaZElS8xWLgUMAg/oFLeewfUz0mu1CblHhhsu15jGkraldkFh8KQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", + "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==", "optional": true }, "node_modules/faye-websocket": { @@ -1387,12 +1426,12 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/firebase-admin": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-11.0.0.tgz", - "integrity": "sha512-x56u+Q1P8QDvQKaYRe29ZUM/3f829cP8tsKCDXOhaIX/GbGfgcdjRhPmCafzlwgCWP5wW9NkOgIhnrw94zucvw==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-11.0.1.tgz", + "integrity": "sha512-rL3wlZbi2Kb/KJgcmj1YHlD4ZhfmhfgRO2YJialxAllm0tj1IQea878hHuBLGmv4DpbW9t9nLvX9kddNR2Y65Q==", "dependencies": { "@fastify/busboy": "^1.1.0", - "@firebase/database-compat": "^0.2.0", + "@firebase/database-compat": "^0.2.3", "@firebase/database-types": "^0.9.7", "@types/node": ">=12.12.47", "jsonwebtoken": "^8.5.1", @@ -1409,9 +1448,9 @@ } }, "node_modules/firebase-functions": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.22.0.tgz", - "integrity": "sha512-d1BxBpT95MhvVqXkpLWDvWbyuX7e2l69cFAiqG3U1XQDaMV88bM9S+Zg7H8i9pitEGFr+76ErjKgrY0n+g3ZDA==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.23.0.tgz", + "integrity": "sha512-/jujnNChTWIuoXK3IPNGYu1zjXF1fYRy88uYbkrJhs3dhK6EdXZi0rX6JUEOCB7h6IkRQvbio+bvtaoI7h+4Lg==", "dependencies": { "@types/cors": "^2.8.5", "@types/express": "4.17.3", @@ -1461,9 +1500,9 @@ } }, "node_modules/flatted": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, "node_modules/forwarded": { @@ -1537,9 +1576,9 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -1597,9 +1636,9 @@ } }, "node_modules/google-auth-library": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.1.0.tgz", - "integrity": "sha512-J/fNXEnqLgbr3kmeUshZCtHQia6ZiNbbrebVzpt/+LTeY6Ka9CtbQvloTjVGVO7nyYbs0KYeuIwgUC/t2Gp1Jw==", + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.5.1.tgz", + "integrity": "sha512-7jNMDRhenfw2HLfL9m0ZP/Jw5hzXygfSprzBdypG3rZ+q2gIUbVC/osrFB7y/Z5dkrUr1mnLoDNlerF+p6VXZA==", "optional": true, "dependencies": { "arrify": "^2.0.0", @@ -1608,7 +1647,7 @@ "fast-text-encoding": "^1.0.0", "gaxios": "^5.0.0", "gcp-metadata": "^5.0.0", - "gtoken": "^6.0.0", + "gtoken": "^6.1.0", "jws": "^4.0.0", "lru-cache": "^6.0.0" }, @@ -1735,9 +1774,9 @@ } }, "node_modules/google-p12-pem": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.0.tgz", - "integrity": "sha512-lRTMn5ElBdDixv4a86bixejPSRk1boRtUowNepeKEVvYiFlkLuAJUVpEz6PfObDHYEKnZWq/9a2zC98xu62A9w==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz", + "integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==", "optional": true, "dependencies": { "node-forge": "^1.3.1" @@ -1750,12 +1789,12 @@ } }, "node_modules/gtoken": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.0.tgz", - "integrity": "sha512-WPZcFw34wh2LUvbCUWI70GDhOlO7qHpSvFHFqq7d3Wvsf8dIJedE0lnUdOmsKuC0NgflKmF0LxIF38vsGeHHiQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", + "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", "optional": true, "dependencies": { - "gaxios": "^4.0.0", + "gaxios": "^5.0.1", "google-p12-pem": "^4.0.0", "jws": "^4.0.0" }, @@ -1763,22 +1802,6 @@ "node": ">=12.0.0" } }, - "node_modules/gtoken/node_modules/gaxios": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.3.tgz", - "integrity": "sha512-gSaYYIO1Y3wUtdfHmjDUZ8LWaxJQpiavzbF5Kq53akSzvmVg0RfyOcFDbO1KJ/KCGRFz2qG+lS81F0nkr7cRJA==", - "optional": true, - "dependencies": { - "abort-controller": "^3.0.0", - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.6.7" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -1980,9 +2003,9 @@ "dev": true }, "node_modules/jose": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz", - "integrity": "sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.6.tgz", + "integrity": "sha512-FVoPY7SflDodE4lknJmbAHSUjLCzE2H1F6MS0RYKMQ8SR+lNccpMf8R4eqkNYyyUjR5qZReOzZo5C5YiHOCjjg==", "dependencies": { "@panva/asn1.js": "^1.0.0" }, @@ -2109,9 +2132,9 @@ } }, "node_modules/jwks-rsa/node_modules/@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", + "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.18", @@ -2545,27 +2568,6 @@ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "optional": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/pumpify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", - "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", - "optional": true, - "dependencies": { - "duplexify": "^4.1.1", - "inherits": "^2.0.3", - "pump": "^3.0.0" - } - }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -2674,9 +2676,9 @@ } }, "node_modules/retry-request": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-5.0.1.tgz", - "integrity": "sha512-lxFKrlBt0OZzCWh/V0uPEN0vlr3OhdeXnpeY5OES+ckslm791Cb1D5P7lJUSnY7J5hiCjcyaUGmzCnIGDCUBig==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-5.0.2.tgz", + "integrity": "sha512-wfI3pk7EE80lCIXprqh7ym48IHYdwmAAzESdbU8Q9l7pnRCk9LEhpbOTNKjz6FARLm/Bl5m+4F0ABxOkYUujSQ==", "optional": true, "dependencies": { "debug": "^4.1.1", @@ -2995,9 +2997,9 @@ "dev": true }, "node_modules/teeny-request": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-8.0.0.tgz", - "integrity": "sha512-6KEYxXI4lQPSDkXzXpPmJPNmo7oqduFFbhOEHf8sfsLbXyCsb+umUjBtMGAKhaSToD8JNCtQutTRefu29K64JA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-8.0.1.tgz", + "integrity": "sha512-q1yTwqoS5aH1pjur3kBbI+wFpiAswdVirHMB3pYT5x/B0d+ulYdrruB/xVtbTEaxJemHu5aTbh11rsOLlFk/ZQ==", "optional": true, "dependencies": { "http-proxy-agent": "^5.0.0", @@ -3273,9 +3275,9 @@ } }, "@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true }, "@babel/highlight": { @@ -3324,6 +3326,12 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -3379,47 +3387,47 @@ "requires": {} }, "@firebase/component": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.16.tgz", - "integrity": "sha512-/pkl77mN9PT7dTSzNu1CrvIvd+z1CdePnEl+VITaeSBs9Ko7ZVvSIlzQLbSwqksXX3bAHpxej0Mg6mVKQiRVSw==", + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.17.tgz", + "integrity": "sha512-mTM5CBSIlmI+i76qU4+DhuExnWtzcPS3cVgObA3VAjliPPr3GrUlTaaa8KBGfxsD27juQxMsYA0TvCR5X+GQ3Q==", "requires": { - "@firebase/util": "1.6.2", + "@firebase/util": "1.6.3", "tslib": "^2.1.0" } }, "@firebase/database": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.13.2.tgz", - "integrity": "sha512-wKkBD4rq6PPv9gl1hNJNpl0R0bwJmXCJfDuvotjXmTcU7kV0AIaJ45GVhULkbSCApAAFC6QUJ91oasDUO1ZVxw==", + "version": "0.13.6", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.13.6.tgz", + "integrity": "sha512-5IZIBw2LT50Z8mwmKYmdX37p+Gg2HgeJsrruZmRyOSVgbfoY4Pg87n1uFx6qWqDmfL6HwQgwcrrQfVIXE3C5SA==", "requires": { "@firebase/auth-interop-types": "0.1.6", - "@firebase/component": "0.5.16", + "@firebase/component": "0.5.17", "@firebase/logger": "0.3.3", - "@firebase/util": "1.6.2", + "@firebase/util": "1.6.3", "faye-websocket": "0.11.4", "tslib": "^2.1.0" } }, "@firebase/database-compat": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.2.2.tgz", - "integrity": "sha512-3wLHJ54WHMhrveCywCMbkspshFezN07PLOIsmqELM1+pmrg3bwMj9u/o3Equ0DwmESMnchp5sMxgzdBUOextJg==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.2.6.tgz", + "integrity": "sha512-Ls1BAODaiDYgeJljrIgSuC7JkFIY/HNhhNYebzZSoGQU62RuvnaO3Qgp2EH6h2LzHyRnycNadfh1suROtPaUIA==", "requires": { - "@firebase/component": "0.5.16", - "@firebase/database": "0.13.2", - "@firebase/database-types": "0.9.10", + "@firebase/component": "0.5.17", + "@firebase/database": "0.13.6", + "@firebase/database-types": "0.9.13", "@firebase/logger": "0.3.3", - "@firebase/util": "1.6.2", + "@firebase/util": "1.6.3", "tslib": "^2.1.0" } }, "@firebase/database-types": { - "version": "0.9.10", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.9.10.tgz", - "integrity": "sha512-2ji6nXRRsY+7hgU6zRhUtK0RmSjVWM71taI7Flgaw+BnopCo/lDF5HSwxp8z7LtiHlvQqeRA3Ozqx5VhlAbiKg==", + "version": "0.9.13", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.9.13.tgz", + "integrity": "sha512-dIJ1zGe3EHMhwcvukTOPzYlFYFIG1Et5Znl7s7y/ZTN2/toARRNnsv1qCKvqevIMYKvIrRsYOYfOXDS8l1YIJA==", "requires": { "@firebase/app-types": "0.7.0", - "@firebase/util": "1.6.2" + "@firebase/util": "1.6.3" } }, "@firebase/logger": { @@ -3431,9 +3439,9 @@ } }, "@firebase/util": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.6.2.tgz", - "integrity": "sha512-VYDqEf/+mS7n0nPj6qJDJYFtKIEfOaTtQeNDsd3x+xp8HWvrbygWOexzeGicLP1dvEzrKr3eQGcJmmmYN3TIsA==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.6.3.tgz", + "integrity": "sha512-FujteO6Zjv6v8A4HS+t7c+PjU0Kaxj+rOnka0BsI/twUaCC9t8EQPmXpWZdk7XfszfahJn2pqsflUWUhtUkRlg==", "requires": { "tslib": "^2.1.0" } @@ -3467,15 +3475,15 @@ "optional": true }, "@google-cloud/promisify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-3.0.0.tgz", - "integrity": "sha512-91ArYvRgXWb73YvEOBMmOcJc0bDRs5yiVHnqkwoG0f3nm7nZuipllz6e7BvFESBvjkDTBC0zMD8QxedUwNLc1A==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-3.0.1.tgz", + "integrity": "sha512-z1CjRjtQyBOYL+5Qr9DdYIfrdLBe746jRTYfaYU6MeXkqp7UfYs/jX16lFFVzZ7PGEJvqZNqYUEtb1mvDww4pA==", "optional": true }, "@google-cloud/storage": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.2.2.tgz", - "integrity": "sha512-KhAOxmGfmELKKn6cdvgGfAi/YBLi19hI1jX3QI7xQmbeajSFMgUKrIPbbyfMIxQPOEQ9vG0MQX1uganlA/HTRA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.5.0.tgz", + "integrity": "sha512-fAWk+NxsgII769YMfq/dDf3vaCuRWkp8aKmBZfi8NPTkKOm24tv8wqb4MQ0XL/I09oLiNqUZZe4q6hqzzQbryA==", "optional": true, "requires": { "@google-cloud/paginator": "^3.0.7", @@ -3493,21 +3501,62 @@ "mime": "^3.0.0", "mime-types": "^2.0.8", "p-limit": "^3.0.1", - "pumpify": "^2.0.0", "retry-request": "^5.0.0", - "stream-events": "^1.0.4", "teeny-request": "^8.0.0", "uuid": "^8.0.0" } }, "@grpc/grpc-js": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.6.7.tgz", - "integrity": "sha512-eBM03pu9hd3VqDQG+kHahiG1x80RGkkqqRb1Pchcwqej/KkAH95gAvKs6laqaHCycYaPK+TKuNQnOz9UXYA8qw==", + "version": "1.6.12", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.6.12.tgz", + "integrity": "sha512-JmvQ03OTSpVd9JTlj/K3IWHSz4Gk/JMLUTtW7Zb0KvO1LcOYGATh5cNuRYzCAeDR3O8wq+q8FZe97eO9MBrkUw==", "optional": true, "requires": { - "@grpc/proto-loader": "^0.6.4", + "@grpc/proto-loader": "^0.7.0", "@types/node": ">=12.12.47" + }, + "dependencies": { + "@grpc/proto-loader": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.2.tgz", + "integrity": "sha512-jCdyLIT/tdQ1zhrbTQnJNK5nbDf0GoBpy5jVNywBzzMDF+Vs6uEaHnfz46dMtDxkvwrF2hzk5Z67goliceH0sA==", + "optional": true, + "requires": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^7.0.0", + "yargs": "^16.2.0" + } + }, + "protobufjs": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.1.tgz", + "integrity": "sha512-d0nMQqS/aT3lfV8bKi9Gbg73vPd2LcDdTDOu6RE/M+h9DY8g1EmDzk3ADPccthEWfTBjkR2oxNdx9Gs8YubT+g==", + "optional": true, + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "dependencies": { + "long": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.0.tgz", + "integrity": "sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w==", + "optional": true + } + } + } } }, "@grpc/proto-loader": { @@ -3631,9 +3680,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.29", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz", - "integrity": "sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==", + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", "requires": { "@types/node": "*", "@types/qs": "*", @@ -3641,17 +3690,17 @@ } }, "@types/jsonwebtoken": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.8.tgz", - "integrity": "sha512-zm6xBQpFDIDM6o9r6HSgDeIcLy82TKWctCXEPbJJcXb5AKmi5BNNdLXneixK4lplX3PqIVcwLBCGE/kAGnlD4A==", + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.9.tgz", + "integrity": "sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==", "requires": { "@types/node": "*" } }, "@types/lodash": { - "version": "4.14.182", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", - "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==", + "version": "4.14.185", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.185.tgz", + "integrity": "sha512-evMDG1bC4rgQg4ku9tKpuMh5iBNEwNa3tf9zRHdP1qlv+1WUg44xat4IxCE14gIpZRGUUWAx2VhItCZc25NfMA==", "dev": true }, "@types/long": { @@ -3661,14 +3710,14 @@ "optional": true }, "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, "@types/node": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.1.tgz", - "integrity": "sha512-CmR8+Tsy95hhwtZBKJBs0/FFq4XX7sDZHlGGf+0q+BRZfMbOTkzkj0AFAuTyXbObDIoanaBBW0+KEW+m3N16Wg==" + "version": "18.7.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", + "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==" }, "@types/qs": { "version": "6.9.7", @@ -3681,11 +3730,11 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", "requires": { - "@types/mime": "^1", + "@types/mime": "*", "@types/node": "*" } }, @@ -3810,9 +3859,9 @@ "optional": true }, "bignumber.js": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", - "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.0.tgz", + "integrity": "sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A==", "optional": true }, "body-parser": { @@ -4082,12 +4131,6 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, "eslint": { "version": "7.19.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.19.0.tgz", @@ -4148,6 +4191,14 @@ "requires": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } } }, "eslint-utils": { @@ -4205,14 +4256,6 @@ "dev": true, "requires": { "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } } }, "esrecurse": { @@ -4222,20 +4265,12 @@ "dev": true, "requires": { "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } } }, "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "esutils": { @@ -4333,9 +4368,9 @@ "dev": true }, "fast-text-encoding": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.4.tgz", - "integrity": "sha512-x6lDDm/tBAzX9kmsPcZsNbvDs3Zey3+scsxaZElS8xWLgUMAg/oFLeewfUz0mu1CblHhhsu15jGkraldkFh8KQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", + "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==", "optional": true }, "faye-websocket": { @@ -4385,12 +4420,12 @@ } }, "firebase-admin": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-11.0.0.tgz", - "integrity": "sha512-x56u+Q1P8QDvQKaYRe29ZUM/3f829cP8tsKCDXOhaIX/GbGfgcdjRhPmCafzlwgCWP5wW9NkOgIhnrw94zucvw==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-11.0.1.tgz", + "integrity": "sha512-rL3wlZbi2Kb/KJgcmj1YHlD4ZhfmhfgRO2YJialxAllm0tj1IQea878hHuBLGmv4DpbW9t9nLvX9kddNR2Y65Q==", "requires": { "@fastify/busboy": "^1.1.0", - "@firebase/database-compat": "^0.2.0", + "@firebase/database-compat": "^0.2.3", "@firebase/database-types": "^0.9.7", "@google-cloud/firestore": "^5.0.2", "@google-cloud/storage": "^6.1.0", @@ -4402,9 +4437,9 @@ } }, "firebase-functions": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.22.0.tgz", - "integrity": "sha512-d1BxBpT95MhvVqXkpLWDvWbyuX7e2l69cFAiqG3U1XQDaMV88bM9S+Zg7H8i9pitEGFr+76ErjKgrY0n+g3ZDA==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.23.0.tgz", + "integrity": "sha512-/jujnNChTWIuoXK3IPNGYu1zjXF1fYRy88uYbkrJhs3dhK6EdXZi0rX6JUEOCB7h6IkRQvbio+bvtaoI7h+4Lg==", "requires": { "@types/cors": "^2.8.5", "@types/express": "4.17.3", @@ -4435,9 +4470,9 @@ } }, "flatted": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, "forwarded": { @@ -4496,9 +4531,9 @@ "optional": true }, "get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -4538,9 +4573,9 @@ } }, "google-auth-library": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.1.0.tgz", - "integrity": "sha512-J/fNXEnqLgbr3kmeUshZCtHQia6ZiNbbrebVzpt/+LTeY6Ka9CtbQvloTjVGVO7nyYbs0KYeuIwgUC/t2Gp1Jw==", + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.5.1.tgz", + "integrity": "sha512-7jNMDRhenfw2HLfL9m0ZP/Jw5hzXygfSprzBdypG3rZ+q2gIUbVC/osrFB7y/Z5dkrUr1mnLoDNlerF+p6VXZA==", "optional": true, "requires": { "arrify": "^2.0.0", @@ -4549,7 +4584,7 @@ "fast-text-encoding": "^1.0.0", "gaxios": "^5.0.0", "gcp-metadata": "^5.0.0", - "gtoken": "^6.0.0", + "gtoken": "^6.1.0", "jws": "^4.0.0", "lru-cache": "^6.0.0" } @@ -4648,38 +4683,23 @@ } }, "google-p12-pem": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.0.tgz", - "integrity": "sha512-lRTMn5ElBdDixv4a86bixejPSRk1boRtUowNepeKEVvYiFlkLuAJUVpEz6PfObDHYEKnZWq/9a2zC98xu62A9w==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz", + "integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==", "optional": true, "requires": { "node-forge": "^1.3.1" } }, "gtoken": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.0.tgz", - "integrity": "sha512-WPZcFw34wh2LUvbCUWI70GDhOlO7qHpSvFHFqq7d3Wvsf8dIJedE0lnUdOmsKuC0NgflKmF0LxIF38vsGeHHiQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", + "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", "optional": true, "requires": { - "gaxios": "^4.0.0", + "gaxios": "^5.0.1", "google-p12-pem": "^4.0.0", "jws": "^4.0.0" - }, - "dependencies": { - "gaxios": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.3.tgz", - "integrity": "sha512-gSaYYIO1Y3wUtdfHmjDUZ8LWaxJQpiavzbF5Kq53akSzvmVg0RfyOcFDbO1KJ/KCGRFz2qG+lS81F0nkr7cRJA==", - "optional": true, - "requires": { - "abort-controller": "^3.0.0", - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.6.7" - } - } } }, "has": { @@ -4829,9 +4849,9 @@ "dev": true }, "jose": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz", - "integrity": "sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.6.tgz", + "integrity": "sha512-FVoPY7SflDodE4lknJmbAHSUjLCzE2H1F6MS0RYKMQ8SR+lNccpMf8R4eqkNYyyUjR5qZReOzZo5C5YiHOCjjg==", "requires": { "@panva/asn1.js": "^1.0.0" } @@ -4941,9 +4961,9 @@ }, "dependencies": { "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", + "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", "requires": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.18", @@ -5290,27 +5310,6 @@ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "optional": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", - "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", - "optional": true, - "requires": { - "duplexify": "^4.1.1", - "inherits": "^2.0.3", - "pump": "^3.0.0" - } - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -5383,9 +5382,9 @@ "optional": true }, "retry-request": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-5.0.1.tgz", - "integrity": "sha512-lxFKrlBt0OZzCWh/V0uPEN0vlr3OhdeXnpeY5OES+ckslm791Cb1D5P7lJUSnY7J5hiCjcyaUGmzCnIGDCUBig==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-5.0.2.tgz", + "integrity": "sha512-wfI3pk7EE80lCIXprqh7ym48IHYdwmAAzESdbU8Q9l7pnRCk9LEhpbOTNKjz6FARLm/Bl5m+4F0ABxOkYUujSQ==", "optional": true, "requires": { "debug": "^4.1.1", @@ -5629,9 +5628,9 @@ } }, "teeny-request": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-8.0.0.tgz", - "integrity": "sha512-6KEYxXI4lQPSDkXzXpPmJPNmo7oqduFFbhOEHf8sfsLbXyCsb+umUjBtMGAKhaSToD8JNCtQutTRefu29K64JA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-8.0.1.tgz", + "integrity": "sha512-q1yTwqoS5aH1pjur3kBbI+wFpiAswdVirHMB3pYT5x/B0d+ulYdrruB/xVtbTEaxJemHu5aTbh11rsOLlFk/ZQ==", "optional": true, "requires": { "http-proxy-agent": "^5.0.0", diff --git a/transport/transport-runtime/src/main/java/com/google/android/datatransport/runtime/ForcedSender.java b/transport/transport-runtime/src/main/java/com/google/android/datatransport/runtime/ForcedSender.java new file mode 100644 index 00000000000..d0a9ef2b8cc --- /dev/null +++ b/transport/transport-runtime/src/main/java/com/google/android/datatransport/runtime/ForcedSender.java @@ -0,0 +1,42 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.android.datatransport.runtime; + +import android.annotation.SuppressLint; +import androidx.annotation.Discouraged; +import androidx.annotation.WorkerThread; +import com.google.android.datatransport.Priority; +import com.google.android.datatransport.Transport; + +@Discouraged( + message = + "TransportRuntime is not a realtime delivery system, don't use unless you absolutely must.") +public final class ForcedSender { + @WorkerThread + public static void sendBlocking(Transport transport, Priority priority) { + @SuppressLint("DiscouragedApi") + TransportContext context = getTransportContextOrThrow(transport).withPriority(priority); + TransportRuntime.getInstance().getUploader().logAndUpdateState(context, 1); + } + + private static TransportContext getTransportContextOrThrow(Transport transport) { + if (transport instanceof TransportImpl) { + return ((TransportImpl) transport).getTransportContext(); + } + throw new IllegalArgumentException("Expected instance of TransportImpl."); + } + + private ForcedSender() {} +} diff --git a/transport/transport-runtime/src/main/java/com/google/android/datatransport/runtime/TransportImpl.java b/transport/transport-runtime/src/main/java/com/google/android/datatransport/runtime/TransportImpl.java index 621363126ce..96d0fb83ca8 100644 --- a/transport/transport-runtime/src/main/java/com/google/android/datatransport/runtime/TransportImpl.java +++ b/transport/transport-runtime/src/main/java/com/google/android/datatransport/runtime/TransportImpl.java @@ -57,4 +57,8 @@ public void schedule(Event event, TransportScheduleCallback callback) { .build(), callback); } + + TransportContext getTransportContext() { + return transportContext; + } } diff --git a/transport/transport-runtime/src/main/java/com/google/android/datatransport/runtime/scheduling/jobscheduling/Uploader.java b/transport/transport-runtime/src/main/java/com/google/android/datatransport/runtime/scheduling/jobscheduling/Uploader.java index ba59ef1eb1a..0ac9017e7f2 100644 --- a/transport/transport-runtime/src/main/java/com/google/android/datatransport/runtime/scheduling/jobscheduling/Uploader.java +++ b/transport/transport-runtime/src/main/java/com/google/android/datatransport/runtime/scheduling/jobscheduling/Uploader.java @@ -17,6 +17,7 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import androidx.annotation.RestrictTo; import androidx.annotation.VisibleForTesting; import com.google.android.datatransport.Encoding; import com.google.android.datatransport.runtime.EncodedPayload; @@ -111,7 +112,8 @@ public void upload(TransportContext transportContext, int attemptNumber, Runnabl }); } - BackendResponse logAndUpdateState(TransportContext transportContext, int attemptNumber) { + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + public BackendResponse logAndUpdateState(TransportContext transportContext, int attemptNumber) { TransportBackend backend = backendRegistry.get(transportContext.getBackendName()); long maxNextRequestWaitMillis = 0; diff --git a/transport/transport-runtime/transport-runtime.gradle b/transport/transport-runtime/transport-runtime.gradle index 240c6720375..2272e16ba95 100644 --- a/transport/transport-runtime/transport-runtime.gradle +++ b/transport/transport-runtime/transport-runtime.gradle @@ -101,7 +101,7 @@ thirdPartyLicenses { dependencies { implementation project(':transport:transport-api') - implementation 'androidx.annotation:annotation:1.1.0' + implementation 'androidx.annotation:annotation:1.3.0' implementation 'javax.inject:javax.inject:1' implementation project(":encoders:firebase-encoders") implementation project(":encoders:firebase-encoders-proto") @@ -132,4 +132,4 @@ dependencies { androidTestImplementation 'org.mockito:mockito-android:2.25.0' androidTestAnnotationProcessor 'com.google.dagger:dagger-compiler:2.27' -} \ No newline at end of file +}