Skip to content

Commit f88c995

Browse files
committed
Merge branch 'master' into rosalyntan.fac-limited
2 parents 14d1506 + 7eea13a commit f88c995

File tree

24 files changed

+579
-431
lines changed

24 files changed

+579
-431
lines changed

.github/workflows/fireperf-e2e.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ jobs:
9393
title: 'FirePerf E2E Test Failures',
9494
body: text,
9595
labels: ['fireperf-e2e-tests'],
96-
assignees: ['jeremyjiang-dev', 'leotianlizhan', 'raymondlam', 'visumickey']
96+
assignees: ['raymondlam', 'visumickey']
9797
});
9898
}
9999
- name: Upload test artifacts

buildSrc/src/main/java/com/google/firebase/gradle/plugins/ModuleVersion.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ enum class PreReleaseVersionType {
6161
* "12.13.1-beta" // 12.13.1-beta01
6262
* ```
6363
*
64-
* @see fromStringsOrNull
6564
* @property type an enum of [PreReleaseVersionType] that identifies the pre-release identifier
6665
* @property build an [Int] that specifies the build number; defaults to one
66+
* @see fromStringsOrNull
6767
*/
6868
data class PreReleaseVersion(val type: PreReleaseVersionType, val build: Int = 1) :
6969
Comparable<PreReleaseVersion> {
@@ -124,11 +124,11 @@ data class PreReleaseVersion(val type: PreReleaseVersionType, val build: Int = 1
124124
*
125125
* To see rules about pre-release (`PRE`) formatting, see [PreReleaseVersion].
126126
*
127-
* @see fromStringOrNull
128127
* @property major An update that represents breaking changes
129128
* @property minor An update that represents new functionality
130129
* @property patch An update that represents bug fixes
131130
* @property pre An update that represents unstable changes not ready for a full release
131+
* @see fromStringOrNull
132132
*/
133133
data class ModuleVersion(
134134
val major: Int,

firebase-config/CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
# Unreleased
2+
* [unchanged] Updated to accommodate the release of the updated
3+
[remote_config] Kotlin extensions library.
4+
5+
## Kotlin
6+
* [feature] Added the `FirebaseRemoteConfig.configUpdates` Kotlin Flow to listen for real-time
7+
config updates.
28

39
# 21.3.0
410
* [feature] Added support for real-time config updates. To learn more, see
511
[Get started with [firebase_remote_config]](/docs/remote-config/get-started?platform=android#add-real-time-listener).
612

7-
813
## Kotlin
914
The Kotlin extensions library transitively includes the updated
1015
`firebase-config` library. The Kotlin extensions library has no additional

firebase-config/bandwagoner/bandwagoner.gradle

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
apply plugin: 'com.android.application'
1818
apply plugin: com.google.firebase.gradle.plugins.ci.device.FirebaseTestLabPlugin
19+
apply plugin: 'org.jetbrains.kotlin.android'
20+
21+
// Uncomment this line after adding a google-services.json file to the project.
22+
// apply plugin: 'com.google.gms.google-services'
1923

2024
android {
2125
compileSdkVersion project.targetSdkVersion
@@ -59,11 +63,16 @@ firebaseTestLab {
5963
}
6064

6165
dependencies {
66+
// Depend on development artifacts for Remote Config.
6267
implementation project(":firebase-config")
63-
// This is required since a project dependency on frc does not expose the Apis of its "implementation" dependencies.
64-
// The alternative would be to make common an "api" dep of remote-config.
65-
// It should not matter for released artifacts.
66-
implementation "com.google.firebase:firebase-common:20.3.1"
68+
implementation project(":firebase-config:ktx")
69+
70+
// This is required since a `project` dependency on frc does not expose the APIs of its
71+
// "implementation" dependencies. The alternative would be to make common an "api" dep of remote-config.
72+
// Released artifacts don't need these dependencies since they don't use `project` to refer
73+
// to Remote Config.
74+
implementation "com.google.firebase:firebase-common:20.3.2"
75+
implementation 'com.google.firebase:firebase-common-ktx:20.3.2'
6776
implementation "com.google.firebase:firebase-components:17.1.0"
6877

6978
implementation project(":firebase-installations-interop")
@@ -75,6 +84,7 @@ dependencies {
7584
// Support Libraries
7685
implementation 'com.google.guava:guava:28.1-android'
7786
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
87+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.6.4"
7888

7989
implementation 'androidx.appcompat:appcompat:1.0.2'
8090
implementation 'androidx.annotation:annotation:1.1.0'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2023 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.googletest.firebase.remoteconfig.bandwagoner
18+
19+
import android.util.Log
20+
import com.google.firebase.ktx.Firebase
21+
import com.google.firebase.remoteconfig.ktx.configUpdates
22+
import com.google.firebase.remoteconfig.ktx.remoteConfig
23+
import java.util.concurrent.CompletableFuture
24+
import kotlinx.coroutines.GlobalScope
25+
import kotlinx.coroutines.flow.catch
26+
import kotlinx.coroutines.future.future
27+
28+
class RealtimeKtListener {
29+
companion object {
30+
private val TAG = "RealtimeListener"
31+
32+
fun listenForUpdatesAsync(): CompletableFuture<Unit> = GlobalScope.future { listenForUpdates() }
33+
34+
private suspend fun listenForUpdates() {
35+
Firebase.remoteConfig.configUpdates
36+
.catch { exception -> Log.w(TAG, "Error listening for updates!", exception) }
37+
.collect { configUpdate ->
38+
if (configUpdate.updatedKeys.contains("welcome_message")) {
39+
Firebase.remoteConfig.activate()
40+
}
41+
}
42+
}
43+
}
44+
}

firebase-config/ktx/api.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.google.firebase.remoteconfig.ktx {
33

44
public final class RemoteConfigKt {
55
method @NonNull public static operator com.google.firebase.remoteconfig.FirebaseRemoteConfigValue get(@NonNull com.google.firebase.remoteconfig.FirebaseRemoteConfig, @NonNull String key);
6+
method @NonNull public static kotlinx.coroutines.flow.Flow<com.google.firebase.remoteconfig.ConfigUpdate> getConfigUpdates(@NonNull com.google.firebase.remoteconfig.FirebaseRemoteConfig);
67
method @NonNull public static com.google.firebase.remoteconfig.FirebaseRemoteConfig getRemoteConfig(@NonNull com.google.firebase.ktx.Firebase);
78
method @NonNull public static com.google.firebase.remoteconfig.FirebaseRemoteConfig remoteConfig(@NonNull com.google.firebase.ktx.Firebase, @NonNull com.google.firebase.FirebaseApp app);
89
method @NonNull public static com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings remoteConfigSettings(@NonNull kotlin.jvm.functions.Function1<? super com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings.Builder,kotlin.Unit> init);

firebase-config/ktx/src/main/kotlin/com/google/firebase/remoteconfig/ktx/RemoteConfig.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,17 @@ import com.google.firebase.components.Component
2020
import com.google.firebase.components.ComponentRegistrar
2121
import com.google.firebase.ktx.Firebase
2222
import com.google.firebase.platforminfo.LibraryVersionComponent
23+
import com.google.firebase.remoteconfig.ConfigUpdate
24+
import com.google.firebase.remoteconfig.ConfigUpdateListener
2325
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
26+
import com.google.firebase.remoteconfig.FirebaseRemoteConfigException
2427
import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings
2528
import com.google.firebase.remoteconfig.FirebaseRemoteConfigValue
29+
import kotlinx.coroutines.cancel
30+
import kotlinx.coroutines.channels.awaitClose
31+
import kotlinx.coroutines.channels.trySendBlocking
32+
import kotlinx.coroutines.flow.Flow
33+
import kotlinx.coroutines.flow.callbackFlow
2634

2735
/** Returns the [FirebaseRemoteConfig] instance of the default [FirebaseApp]. */
2836
val Firebase.remoteConfig: FirebaseRemoteConfig
@@ -45,6 +53,31 @@ fun remoteConfigSettings(
4553
return builder.build()
4654
}
4755

56+
/**
57+
* Starts listening for config updates from the Remote Config backend and emits [ConfigUpdate]s via
58+
* a [Flow]. See [FirebaseRemoteConfig.addOnConfigUpdateListener] for more information.
59+
*
60+
* - When the returned flow starts being collected, an [ConfigUpdateListener] will be attached.
61+
* - When the flow completes, the listener will be removed. If there are no attached listeners, the
62+
* connection to the Remote Config backend will be closed.
63+
*/
64+
val FirebaseRemoteConfig.configUpdates
65+
get() = callbackFlow {
66+
val registration =
67+
addOnConfigUpdateListener(
68+
object : ConfigUpdateListener {
69+
override fun onUpdate(configUpdate: ConfigUpdate) {
70+
schedule { trySendBlocking(configUpdate) }
71+
}
72+
73+
override fun onError(error: FirebaseRemoteConfigException) {
74+
cancel(message = "Error listening for config updates.", cause = error)
75+
}
76+
}
77+
)
78+
awaitClose { registration.remove() }
79+
}
80+
4881
internal const val LIBRARY_NAME: String = "fire-cfg-ktx"
4982

5083
/** @suppress */

firebase-config/src/main/java/com/google/firebase/remoteconfig/FirebaseRemoteConfig.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,15 @@ void startLoadingConfigsFromDisk() {
582582
fetchedConfigsCache.get();
583583
}
584584

585+
/**
586+
* Execute a runnable in Remote Config's background thread pool.
587+
*
588+
* @hide
589+
*/
590+
public void schedule(Runnable runnable) {
591+
executor.execute(runnable);
592+
}
593+
585594
/**
586595
* Processes the result of the put task that persists activated configs. If the task is
587596
* successful, clears the fetched cache and updates the ABT SDK with the current experiments.

firebase-database/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
version=20.1.1
15+
version=20.2.0
1616
latestReleasedVersion=20.1.0
1717
android.enableUnitTestBinaryResources=true

firebase-perf/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Unreleased
22
* [changed] Updated javalite, protoc, protobufjavautil to 3.21.11.
3+
* [changed] Updated [perfmon] to use Double precision for sampling.
34

45
# 20.3.1
56
* [changed] Migrated [perfmon] to use standard Firebase executors.

firebase-perf/src/main/java/com/google/firebase/perf/config/ConfigResolver.java

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -286,22 +286,22 @@ private boolean isFireperfSdkVersionInList(String versions) {
286286
}
287287

288288
/** Returns what percentage of Traces should be collected, range is [0.00f, 1.00f]. */
289-
public float getTraceSamplingRate() {
289+
public double getTraceSamplingRate() {
290290
// Order of precedence is:
291291
// 1. If the value exists through Firebase Remote Config, cache and return this value.
292292
// 2. If the value exists in device cache, return this value.
293293
// 3. Otherwise, return default value.
294294
TraceSamplingRate config = TraceSamplingRate.getInstance();
295295

296296
// 1. Reads value from Firebase Remote Config, saves this value in cache layer if valid.
297-
Optional<Float> rcValue = getRemoteConfigFloat(config);
297+
Optional<Double> rcValue = getRemoteConfigDouble(config);
298298
if (rcValue.isAvailable() && isSamplingRateValid(rcValue.get())) {
299299
deviceCacheManager.setValue(config.getDeviceCacheFlag(), rcValue.get());
300300
return rcValue.get();
301301
}
302302

303303
// 2. Reads value from cache layer.
304-
Optional<Float> deviceCacheValue = getDeviceCacheFloat(config);
304+
Optional<Double> deviceCacheValue = getDeviceCacheDouble(config);
305305
if (deviceCacheValue.isAvailable() && isSamplingRateValid(deviceCacheValue.get())) {
306306
return deviceCacheValue.get();
307307
}
@@ -311,22 +311,22 @@ public float getTraceSamplingRate() {
311311
}
312312

313313
/** Returns what percentage of NetworkRequest should be collected, range is [0.00f, 1.00f]. */
314-
public float getNetworkRequestSamplingRate() {
314+
public double getNetworkRequestSamplingRate() {
315315
// Order of precedence is:
316316
// 1. If the value exists through Firebase Remote Config, cache and return this value.
317317
// 2. If the value exists in device cache, return this value.
318318
// 3. Otherwise, return default value.
319319
NetworkRequestSamplingRate config = NetworkRequestSamplingRate.getInstance();
320320

321321
// 1. Reads value from Firebase Remote Config, saves this value in cache layer if valid.
322-
Optional<Float> rcValue = getRemoteConfigFloat(config);
322+
Optional<Double> rcValue = getRemoteConfigDouble(config);
323323
if (rcValue.isAvailable() && isSamplingRateValid(rcValue.get())) {
324324
deviceCacheManager.setValue(config.getDeviceCacheFlag(), rcValue.get());
325325
return rcValue.get();
326326
}
327327

328328
// 2. Reads value from cache layer.
329-
Optional<Float> deviceCacheValue = getDeviceCacheFloat(config);
329+
Optional<Double> deviceCacheValue = getDeviceCacheDouble(config);
330330
if (deviceCacheValue.isAvailable() && isSamplingRateValid(deviceCacheValue.get())) {
331331
return deviceCacheValue.get();
332332
}
@@ -336,7 +336,7 @@ public float getNetworkRequestSamplingRate() {
336336
}
337337

338338
/** Returns what percentage of Session gauge should be collected, range is [0.00f, 1.00f]. */
339-
public float getSessionsSamplingRate() {
339+
public double getSessionsSamplingRate() {
340340
// Order of precedence is:
341341
// 1. If the value exists in Android Manifest, convert from [0.00f, 100.00f] to [0.00f, 1.00f]
342342
// and return this value.
@@ -346,24 +346,24 @@ public float getSessionsSamplingRate() {
346346
SessionsSamplingRate config = SessionsSamplingRate.getInstance();
347347

348348
// 1. Reads value in Android Manifest (it is set by developers during build time).
349-
Optional<Float> metadataValue = getMetadataFloat(config);
349+
Optional<Double> metadataValue = getMetadataDouble(config);
350350
if (metadataValue.isAvailable()) {
351351
// Sampling percentage from metadata needs to convert from [0.00f, 100.00f] to [0.00f, 1.00f].
352-
float samplingRate = metadataValue.get() / 100.0f;
352+
double samplingRate = metadataValue.get() / 100;
353353
if (isSamplingRateValid(samplingRate)) {
354354
return samplingRate;
355355
}
356356
}
357357

358358
// 2. Reads value from Firebase Remote Config, saves this value in cache layer if valid.
359-
Optional<Float> rcValue = getRemoteConfigFloat(config);
359+
Optional<Double> rcValue = getRemoteConfigDouble(config);
360360
if (rcValue.isAvailable() && isSamplingRateValid(rcValue.get())) {
361361
deviceCacheManager.setValue(config.getDeviceCacheFlag(), rcValue.get());
362362
return rcValue.get();
363363
}
364364

365365
// 3. Reads value from cache layer.
366-
Optional<Float> deviceCacheValue = getDeviceCacheFloat(config);
366+
Optional<Double> deviceCacheValue = getDeviceCacheDouble(config);
367367
if (deviceCacheValue.isAvailable() && isSamplingRateValid(deviceCacheValue.get())) {
368368
return deviceCacheValue.get();
369369
}
@@ -732,7 +732,7 @@ public String getAndCacheLogSourceName() {
732732
}
733733

734734
/** Returns what percentage of fragment traces should be collected, range is [0.00f, 1.00f]. */
735-
public float getFragmentSamplingRate() {
735+
public double getFragmentSamplingRate() {
736736
// Order of precedence is:
737737
// 1. If the value exists in Android Manifest, convert from [0.00f, 100.00f] to [0.00f, 1.00f]
738738
// and return this value.
@@ -742,24 +742,24 @@ public float getFragmentSamplingRate() {
742742
FragmentSamplingRate config = FragmentSamplingRate.getInstance();
743743

744744
// 1. Reads value in Android Manifest (it is set by developers during build time).
745-
Optional<Float> metadataValue = getMetadataFloat(config);
745+
Optional<Double> metadataValue = getMetadataDouble(config);
746746
if (metadataValue.isAvailable()) {
747747
// Sampling percentage from metadata needs to convert from [0.00f, 100.00f] to [0.00f, 1.00f].
748-
float samplingRate = metadataValue.get() / 100.0f;
748+
double samplingRate = metadataValue.get() / 100.0f;
749749
if (isSamplingRateValid(samplingRate)) {
750750
return samplingRate;
751751
}
752752
}
753753

754754
// 2. Reads value from Firebase Remote Config, saves this value in cache layer if valid.
755-
Optional<Float> rcValue = getRemoteConfigFloat(config);
755+
Optional<Double> rcValue = getRemoteConfigDouble(config);
756756
if (rcValue.isAvailable() && isSamplingRateValid(rcValue.get())) {
757757
deviceCacheManager.setValue(config.getDeviceCacheFlag(), rcValue.get());
758758
return rcValue.get();
759759
}
760760

761761
// 3. Reads value from cache layer.
762-
Optional<Float> deviceCacheValue = getDeviceCacheFloat(config);
762+
Optional<Double> deviceCacheValue = getDeviceCacheDouble(config);
763763
if (deviceCacheValue.isAvailable() && isSamplingRateValid(deviceCacheValue.get())) {
764764
return deviceCacheValue.get();
765765
}
@@ -807,17 +807,17 @@ private Optional<Boolean> getMetadataBoolean(ConfigurationFlag<Boolean> config)
807807
return metadataBundle.getBoolean(config.getMetadataFlag());
808808
}
809809

810-
private Optional<Float> getMetadataFloat(ConfigurationFlag<Float> config) {
811-
return metadataBundle.getFloat(config.getMetadataFlag());
810+
private Optional<Double> getMetadataDouble(ConfigurationFlag<Double> config) {
811+
return metadataBundle.getDouble(config.getMetadataFlag());
812812
}
813813

814814
private Optional<Long> getMetadataLong(ConfigurationFlag<Long> config) {
815815
return metadataBundle.getLong(config.getMetadataFlag());
816816
}
817817

818818
// Helper functions for interaction with Firebase Remote Config.
819-
private Optional<Float> getRemoteConfigFloat(ConfigurationFlag<Float> config) {
820-
return remoteConfigManager.getFloat(config.getRemoteConfigFlag());
819+
private Optional<Double> getRemoteConfigDouble(ConfigurationFlag<Double> config) {
820+
return remoteConfigManager.getDouble(config.getRemoteConfigFlag());
821821
}
822822

823823
private Optional<Long> getRemoteConfigLong(ConfigurationFlag<Long> config) {
@@ -841,8 +841,8 @@ private Long getRemoteConfigValue(ConfigurationFlag<Long> configFlag) {
841841
}
842842

843843
// Helper functions for interaction with Device Caching layer.
844-
private Optional<Float> getDeviceCacheFloat(ConfigurationFlag<Float> config) {
845-
return deviceCacheManager.getFloat(config.getDeviceCacheFlag());
844+
private Optional<Double> getDeviceCacheDouble(ConfigurationFlag<Double> config) {
845+
return deviceCacheManager.getDouble(config.getDeviceCacheFlag());
846846
}
847847

848848
private Optional<Long> getDeviceCacheLong(ConfigurationFlag<Long> config) {
@@ -858,7 +858,7 @@ private Optional<String> getDeviceCacheString(ConfigurationFlag<String> config)
858858
}
859859

860860
// Helper functions for config value validation.
861-
private boolean isSamplingRateValid(float samplingRate) {
861+
private boolean isSamplingRateValid(double samplingRate) {
862862
return MIN_SAMPLING_RATE <= samplingRate && samplingRate <= MAX_SAMPLING_RATE;
863863
}
864864

0 commit comments

Comments
 (0)