Skip to content

Commit 90d57dd

Browse files
committed
Merge branch 'master' into mila/BloomFilter
2 parents 97dafee + 0a73fdb commit 90d57dd

34 files changed

+2457
-54
lines changed

.github/workflows/build-release-artifacts.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ on:
88

99
jobs:
1010
build-artifacts:
11-
runs-on: ubuntu-latest
11+
# TODO(b/271315039) - Revert back to ubuntu when fixed
12+
runs-on: macos-latest
1213
env:
1314
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1415
steps:

firebase-appdistribution/firebase-appdistribution.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ dependencies {
5252
implementation 'com.google.firebase:firebase-common:20.3.1'
5353
testImplementation project(path: ':firebase-appdistribution')
5454
testImplementation project(':integ-testing')
55-
runtimeOnly project(':firebase-installations')
55+
runtimeOnly 'com.google.firebase:firebase-installations:17.1.2'
5656

5757
implementation libs.javax.inject
5858
vendor (libs.dagger.dagger) {

firebase-appdistribution/test-app/test-app.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ dependencies {
7676

7777
// In this test project we also need to explicitly declare these dependencies
7878
implementation project(':firebase-appdistribution-api')
79-
implementation project(':firebase-common:ktx')
79+
implementation 'com.google.firebase:firebase-common-ktx:20.3.1'
8080
implementation "com.google.android.gms:play-services-tasks:18.0.2"
8181

8282
// Beta flavor uses the full implementation

firebase-config/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Unreleased
2+
* [feature] Added support for real-time config updates. To learn more, see [Get started with Firebase Remote Config](https://firebase.google.com/docs/remote-config/get-started?platform=android).
23

34
# 21.2.1
45
* [changed] Migrated [remote_config] to use standard Firebase executors.

firebase-config/api.txt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,24 @@
11
// Signature format: 2.0
22
package com.google.firebase.remoteconfig {
33

4+
@com.google.auto.value.AutoValue public abstract class ConfigUpdate {
5+
ctor public ConfigUpdate();
6+
method @NonNull public static com.google.firebase.remoteconfig.ConfigUpdate create(@NonNull java.util.Set<java.lang.String>);
7+
method @NonNull public abstract java.util.Set<java.lang.String> getUpdatedKeys();
8+
}
9+
10+
public interface ConfigUpdateListener {
11+
method public void onError(@NonNull com.google.firebase.remoteconfig.FirebaseRemoteConfigException);
12+
method public void onUpdate(@NonNull com.google.firebase.remoteconfig.ConfigUpdate);
13+
}
14+
15+
public interface ConfigUpdateListenerRegistration {
16+
method public void remove();
17+
}
18+
419
public class FirebaseRemoteConfig {
520
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Boolean> activate();
21+
method @NonNull public com.google.firebase.remoteconfig.ConfigUpdateListenerRegistration addOnConfigUpdateListener(@NonNull com.google.firebase.remoteconfig.ConfigUpdateListener);
622
method @NonNull public com.google.android.gms.tasks.Task<com.google.firebase.remoteconfig.FirebaseRemoteConfigInfo> ensureInitialized();
723
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> fetch();
824
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> fetch(long);
@@ -38,11 +54,25 @@ package com.google.firebase.remoteconfig {
3854
public class FirebaseRemoteConfigClientException extends com.google.firebase.remoteconfig.FirebaseRemoteConfigException {
3955
ctor public FirebaseRemoteConfigClientException(@NonNull String);
4056
ctor public FirebaseRemoteConfigClientException(@NonNull String, @Nullable Throwable);
57+
ctor public FirebaseRemoteConfigClientException(@NonNull String, @NonNull com.google.firebase.remoteconfig.FirebaseRemoteConfigException.Code);
58+
ctor public FirebaseRemoteConfigClientException(@NonNull String, @Nullable Throwable, @NonNull com.google.firebase.remoteconfig.FirebaseRemoteConfigException.Code);
4159
}
4260

4361
public class FirebaseRemoteConfigException extends com.google.firebase.FirebaseException {
4462
ctor public FirebaseRemoteConfigException(@NonNull String);
4563
ctor public FirebaseRemoteConfigException(@NonNull String, @Nullable Throwable);
64+
ctor public FirebaseRemoteConfigException(@NonNull String, @NonNull com.google.firebase.remoteconfig.FirebaseRemoteConfigException.Code);
65+
ctor public FirebaseRemoteConfigException(@NonNull String, @Nullable Throwable, @NonNull com.google.firebase.remoteconfig.FirebaseRemoteConfigException.Code);
66+
method @NonNull public com.google.firebase.remoteconfig.FirebaseRemoteConfigException.Code getCode();
67+
}
68+
69+
public enum FirebaseRemoteConfigException.Code {
70+
method public int value();
71+
enum_constant public static final com.google.firebase.remoteconfig.FirebaseRemoteConfigException.Code CONFIG_UPDATE_MESSAGE_INVALID;
72+
enum_constant public static final com.google.firebase.remoteconfig.FirebaseRemoteConfigException.Code CONFIG_UPDATE_NOT_FETCHED;
73+
enum_constant public static final com.google.firebase.remoteconfig.FirebaseRemoteConfigException.Code CONFIG_UPDATE_STREAM_ERROR;
74+
enum_constant public static final com.google.firebase.remoteconfig.FirebaseRemoteConfigException.Code CONFIG_UPDATE_UNAVAILABLE;
75+
enum_constant public static final com.google.firebase.remoteconfig.FirebaseRemoteConfigException.Code UNKNOWN;
4676
}
4777

4878
public class FirebaseRemoteConfigFetchThrottledException extends com.google.firebase.remoteconfig.FirebaseRemoteConfigException {
@@ -59,6 +89,10 @@ package com.google.firebase.remoteconfig {
5989
public class FirebaseRemoteConfigServerException extends com.google.firebase.remoteconfig.FirebaseRemoteConfigException {
6090
ctor public FirebaseRemoteConfigServerException(int, @NonNull String);
6191
ctor public FirebaseRemoteConfigServerException(int, @NonNull String, @Nullable Throwable);
92+
ctor public FirebaseRemoteConfigServerException(@NonNull String, @NonNull com.google.firebase.remoteconfig.FirebaseRemoteConfigException.Code);
93+
ctor public FirebaseRemoteConfigServerException(int, @NonNull String, @NonNull com.google.firebase.remoteconfig.FirebaseRemoteConfigException.Code);
94+
ctor public FirebaseRemoteConfigServerException(@NonNull String, @Nullable Throwable, @NonNull com.google.firebase.remoteconfig.FirebaseRemoteConfigException.Code);
95+
ctor public FirebaseRemoteConfigServerException(int, @NonNull String, @Nullable Throwable, @NonNull com.google.firebase.remoteconfig.FirebaseRemoteConfigException.Code);
6296
method public int getHttpStatusCode();
6397
}
6498

firebase-config/firebase-config.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,11 @@ dependencies {
5959
implementation 'com.google.firebase:firebase-measurement-connector:18.0.0'
6060
implementation 'com.google.android.gms:play-services-tasks:18.0.1'
6161

62+
compileOnly 'com.google.auto.value:auto-value-annotations:1.6.6'
6263
compileOnly 'com.google.code.findbugs:jsr305:3.0.2'
6364

65+
annotationProcessor 'com.google.auto.value:auto-value:1.6.6'
66+
6467
javadocClasspath 'com.google.auto.value:auto-value-annotations:1.6.6'
6568

6669
testImplementation 'org.mockito:mockito-core:2.25.0'

firebase-config/ktx/src/test/kotlin/com/google/firebase/remoteconfig/TestConstructorUtil.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.google.firebase.remoteconfig.internal.ConfigCacheClient
2222
import com.google.firebase.remoteconfig.internal.ConfigFetchHandler
2323
import com.google.firebase.remoteconfig.internal.ConfigGetParameterHandler
2424
import com.google.firebase.remoteconfig.internal.ConfigMetadataClient
25+
import com.google.firebase.remoteconfig.internal.ConfigRealtimeHandler
2526
import java.util.concurrent.Executor
2627

2728
// This method is a workaround for testing. It enable us to create a FirebaseRemoteConfig object
@@ -37,7 +38,8 @@ fun createRemoteConfig(
3738
defaultConfigsCache: ConfigCacheClient,
3839
fetchHandler: ConfigFetchHandler,
3940
getHandler: ConfigGetParameterHandler,
40-
frcMetadata: ConfigMetadataClient
41+
frcMetadata: ConfigMetadataClient,
42+
realtimeHandler: ConfigRealtimeHandler
4143
): FirebaseRemoteConfig {
4244
return FirebaseRemoteConfig(
4345
context,
@@ -50,6 +52,7 @@ fun createRemoteConfig(
5052
defaultConfigsCache,
5153
fetchHandler,
5254
getHandler,
53-
frcMetadata
55+
frcMetadata,
56+
realtimeHandler
5457
)
5558
}

firebase-config/ktx/src/test/kotlin/com/google/firebase/remoteconfig/ktx/RemoteConfigTests.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import com.google.firebase.remoteconfig.internal.ConfigCacheClient
3131
import com.google.firebase.remoteconfig.internal.ConfigFetchHandler
3232
import com.google.firebase.remoteconfig.internal.ConfigGetParameterHandler
3333
import com.google.firebase.remoteconfig.internal.ConfigMetadataClient
34+
import com.google.firebase.remoteconfig.internal.ConfigRealtimeHandler
3435
import org.junit.After
3536
import org.junit.Before
3637
import org.junit.Test
@@ -138,7 +139,8 @@ class ConfigTests : BaseTestCase() {
138139
defaultConfigsCache = mock(ConfigCacheClient::class.java),
139140
fetchHandler = mock(ConfigFetchHandler::class.java),
140141
getHandler = mockGetHandler,
141-
frcMetadata = mock(ConfigMetadataClient::class.java)
142+
frcMetadata = mock(ConfigMetadataClient::class.java),
143+
realtimeHandler = mock(ConfigRealtimeHandler::class.java)
142144
)
143145

144146
`when`(mockGetHandler.getValue("KEY")).thenReturn(StringRemoteConfigValue("non default value"))

firebase-config/src/androidTest/java/com/google/firebase/remoteconfig/FirebaseRemoteConfigIntegrationTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.google.firebase.remoteconfig.internal.ConfigFetchHandler;
3737
import com.google.firebase.remoteconfig.internal.ConfigGetParameterHandler;
3838
import com.google.firebase.remoteconfig.internal.ConfigMetadataClient;
39+
import com.google.firebase.remoteconfig.internal.ConfigRealtimeHandler;
3940
import java.util.Date;
4041
import java.util.HashMap;
4142
import java.util.Map;
@@ -59,6 +60,7 @@ public class FirebaseRemoteConfigIntegrationTest {
5960
@Mock private ConfigFetchHandler mockFetchHandler;
6061
@Mock private ConfigGetParameterHandler mockGetHandler;
6162
@Mock private ConfigMetadataClient metadataClient;
63+
@Mock private ConfigRealtimeHandler mockConfigRealtimeHandler;
6264

6365
@Mock private ConfigCacheClient mockFireperfFetchedCache;
6466
@Mock private ConfigCacheClient mockFireperfActivatedCache;
@@ -108,7 +110,8 @@ public void setUp() {
108110
mockDefaultsCache,
109111
mockFetchHandler,
110112
mockGetHandler,
111-
metadataClient);
113+
metadataClient,
114+
mockConfigRealtimeHandler);
112115
}
113116

114117
@Test
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
//
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.remoteconfig;
16+
17+
import androidx.annotation.NonNull;
18+
import com.google.auto.value.AutoValue;
19+
import java.util.Set;
20+
21+
/**
22+
* Information about the updated config passed to the {@code onUpdate} callback of {@link
23+
* ConfigUpdateListener}.
24+
*/
25+
@AutoValue
26+
public abstract class ConfigUpdate {
27+
@NonNull
28+
/** @hide */
29+
public static ConfigUpdate create(@NonNull Set<String> updatedKeys) {
30+
return new AutoValue_ConfigUpdate(updatedKeys);
31+
}
32+
33+
/**
34+
* Parameter keys whose values have been updated from the currently activated values. Includes
35+
* keys that are added, deleted, and whose value, value source, or metadata has changed.
36+
*/
37+
@NonNull
38+
public abstract Set<String> getUpdatedKeys();
39+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
//
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.remoteconfig;
16+
17+
import androidx.annotation.NonNull;
18+
import javax.annotation.Nonnull;
19+
20+
/**
21+
* Event listener interface for real-time RC updates. Implement {@code ConfigUpdateListner} to call
22+
* {@link com.google.firebase.remoteconfig.FirebaseRemoteConfig#addOnConfigUpdateListener}.
23+
*/
24+
public interface ConfigUpdateListener {
25+
/**
26+
* Callback for when a new config has been automatically fetched from the backend and has changed
27+
* from the activated config.
28+
*
29+
* @param configUpdate A {@link ConfigUpdate} with information about the updated config, including
30+
* the set of updated parameters.
31+
*/
32+
void onUpdate(@NonNull ConfigUpdate configUpdate);
33+
34+
/**
35+
* Callback for when an error occurs while listening or fetching a config update.
36+
*
37+
* @param error A {@link FirebaseRemoteConfigException} with information about the error.
38+
*/
39+
void onError(@Nonnull FirebaseRemoteConfigException error);
40+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
//
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.remoteconfig;
16+
17+
/**
18+
* Listener registration returned by {@link
19+
* com.google.firebase.remoteconfig.FirebaseRemoteConfig#addOnConfigUpdateListener}.
20+
*
21+
* <p>Calling {@link ConfigUpdateListenerRegistration#remove()} stops the listener from receiving
22+
* config updates and unregisters itself. If remove is called and no other listener registrations
23+
* remain, the connection to the Remote Config backend is closed. Subsequently calling {@link
24+
* com.google.firebase.remoteconfig.FirebaseRemoteConfig#addOnConfigUpdateListener} will re-open the
25+
* connection.
26+
*/
27+
public interface ConfigUpdateListenerRegistration {
28+
29+
/**
30+
* Removes the listener being tracked by this {@code ConfigUpdateListenerRegistration}. After the
31+
* initial call, subsequent calls to {@code remove()} have no effect.
32+
*/
33+
public void remove();
34+
}

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

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.google.firebase.remoteconfig.internal.ConfigFetchHandler.FetchResponse;
3535
import com.google.firebase.remoteconfig.internal.ConfigGetParameterHandler;
3636
import com.google.firebase.remoteconfig.internal.ConfigMetadataClient;
37+
import com.google.firebase.remoteconfig.internal.ConfigRealtimeHandler;
3738
import com.google.firebase.remoteconfig.internal.DefaultsXmlParser;
3839
import java.util.ArrayList;
3940
import java.util.HashMap;
@@ -152,6 +153,7 @@ public static FirebaseRemoteConfig getInstance(@NonNull FirebaseApp app) {
152153
private final ConfigGetParameterHandler getHandler;
153154
private final ConfigMetadataClient frcMetadata;
154155
private final FirebaseInstallationsApi firebaseInstallations;
156+
private final ConfigRealtimeHandler configRealtimeHandler;
155157

156158
/**
157159
* Firebase Remote Config constructor.
@@ -169,7 +171,8 @@ public static FirebaseRemoteConfig getInstance(@NonNull FirebaseApp app) {
169171
ConfigCacheClient defaultConfigsCache,
170172
ConfigFetchHandler fetchHandler,
171173
ConfigGetParameterHandler getHandler,
172-
ConfigMetadataClient frcMetadata) {
174+
ConfigMetadataClient frcMetadata,
175+
ConfigRealtimeHandler configRealtimeHandler) {
173176
this.context = context;
174177
this.firebaseApp = firebaseApp;
175178
this.firebaseInstallations = firebaseInstallations;
@@ -181,6 +184,7 @@ public static FirebaseRemoteConfig getInstance(@NonNull FirebaseApp app) {
181184
this.fetchHandler = fetchHandler;
182185
this.getHandler = getHandler;
183186
this.frcMetadata = frcMetadata;
187+
this.configRealtimeHandler = configRealtimeHandler;
184188
}
185189

186190
/**
@@ -544,6 +548,29 @@ public Task<Void> reset() {
544548
});
545549
}
546550

551+
/**
552+
* Start listening for real-time config updates from the Remote Config backend and automatically
553+
* fetch updates from the RC backend when they are available.
554+
*
555+
* <p>If a connection to the Remote Config backend is not already open, calling this method will
556+
* open it. Multiple listeners can be added by calling this method again, but subsequent calls
557+
* re-use the same connection to the backend.
558+
*
559+
* <p>Note: Real-time Remote Config requires the Firebase Remote Config Realtime API. See the <a
560+
* href="https://firebase.google.com/docs/remote-config/get-started">Remote Config Get Started
561+
* </a> guide to enable the API.
562+
*
563+
* @param configUpdateListener A {@link ConfigUpdateListener} that can be used to respond to
564+
* config updates when they're fetched.
565+
* @return A {@link ConfigUpdateListenerRegistration} that allows the user to remove the added
566+
* {@code configUpdateListener} and close the connection when there are no more listeners.
567+
*/
568+
@NonNull
569+
public ConfigUpdateListenerRegistration addOnConfigUpdateListener(
570+
@NonNull ConfigUpdateListener configUpdateListener) {
571+
return configRealtimeHandler.addRealtimeConfigUpdateListener(configUpdateListener);
572+
}
573+
547574
/**
548575
* Loads all the configs from disk by calling {@link ConfigCacheClient#get} on each cache client.
549576
*
@@ -630,6 +657,16 @@ void updateAbtWithActivatedExperiments(@NonNull JSONArray abtExperiments) {
630657
}
631658
}
632659

660+
/**
661+
* Changes background state of the real-time handler depending on if the app is in the foreground
662+
* or not.
663+
*
664+
* @hide
665+
*/
666+
void setConfigUpdateBackgroundState(boolean backgroundState) {
667+
configRealtimeHandler.setBackgroundState(backgroundState);
668+
}
669+
633670
/**
634671
* Converts a JSON array of Firebase A/B Testing experiments into a Java list of String maps.
635672
*

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,21 @@ public FirebaseRemoteConfigClientException(
3434
@NonNull String detailMessage, @Nullable Throwable cause) {
3535
super(detailMessage, cause);
3636
}
37+
38+
/**
39+
* Creates a Firebase Remote Config client exception with the given message and
40+
* FirebaseRemoteConfigException code.
41+
*/
42+
public FirebaseRemoteConfigClientException(@NonNull String detailMessage, @NonNull Code code) {
43+
super(detailMessage, code);
44+
}
45+
46+
/**
47+
* Creates a Firebase Remote Config client exception with the given message, exception cause, and
48+
* FirebaseRemoteConfigException code.
49+
*/
50+
public FirebaseRemoteConfigClientException(
51+
@NonNull String detailMessage, @Nullable Throwable cause, @NonNull Code code) {
52+
super(detailMessage, cause, code);
53+
}
3754
}

0 commit comments

Comments
 (0)