Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
86ee29c
Add support for custom signals
tusharkhandelwal8 Oct 15, 2024
b241027
Add support for custom signals
tusharkhandelwal8 Oct 15, 2024
bb8336a
Merge remote-tracking branch 'origin/tushar-khandelwal/rc-custom-targ…
tusharkhandelwal8 Oct 15, 2024
ff596ae
Fix lint and build errors.
tusharkhandelwal8 Oct 25, 2024
2a678f6
Fix lint and build errors.
tusharkhandelwal8 Oct 25, 2024
bd05e9d
Merge remote-tracking branch 'origin/tushar-khandelwal/rc-custom-targ…
tusharkhandelwal8 Oct 25, 2024
60ae034
update the API definition file to include setCustomSignals
tusharkhandelwal8 Oct 25, 2024
d1cac74
Add limits, input validation, and unit tests for custom signals
tusharkhandelwal8 Nov 5, 2024
07ae4d4
Merge branch 'refs/heads/main' into tushar-khandelwal/rc-custom-targe…
tusharkhandelwal8 Nov 5, 2024
917a462
Rename ConfigMetadataClient to ConfigSharedPrefsClient in a different…
tusharkhandelwal8 Nov 6, 2024
deb3d84
Rename ConfigMetadataClient to ConfigSharedPrefsClient in a different…
tusharkhandelwal8 Nov 6, 2024
1e172a4
Merge remote-tracking branch 'origin/tushar-khandelwal/rc-custom-targ…
tusharkhandelwal8 Nov 6, 2024
92814b7
Log warnings for invalid custom signals.
tusharkhandelwal8 Nov 18, 2024
288dcd1
Add CustomSignals type for restricted values in setCustomSignals.
tusharkhandelwal8 Nov 21, 2024
88f268f
Add put(String, double) to the CustomSignals.Builder API definition
tusharkhandelwal8 Nov 21, 2024
ccd4b2e
Fix Formating
tusharkhandelwal8 Nov 22, 2024
5a15867
Fix Formating for custom signal limits
tusharkhandelwal8 Nov 22, 2024
21a39c5
Rename ConfigMetadataClient to ConfigSharedPrefsClient (#6440)
tusharkhandelwal8 Nov 23, 2024
3e94fe3
Improve Kotlin API, add logs and tests
tusharkhandelwal8 Nov 26, 2024
5a41f0d
Update API definition file to include kotlin
tusharkhandelwal8 Nov 26, 2024
becb76d
Merge branch 'refs/heads/remoteConfigCustomTargeting' into tushar-kha…
tusharkhandelwal8 Nov 27, 2024
c6b9c56
Update test and rename customSignalsMap to customSignals
tusharkhandelwal8 Dec 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions firebase-config/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ package com.google.firebase.remoteconfig {
method @NonNull public com.google.firebase.remoteconfig.FirebaseRemoteConfigValue getValue(@NonNull String);
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> reset();
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> setConfigSettingsAsync(@NonNull com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings);
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> setCustomSignals(@NonNull java.util.Map<java.lang.String,java.lang.Object>);
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> setDefaultsAsync(@NonNull java.util.Map<java.lang.String,java.lang.Object>);
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> setDefaultsAsync(@XmlRes int);
field public static final boolean DEFAULT_VALUE_FOR_BOOLEAN = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import com.google.firebase.installations.FirebaseInstallationsApi
import com.google.firebase.remoteconfig.internal.ConfigCacheClient
import com.google.firebase.remoteconfig.internal.ConfigFetchHandler
import com.google.firebase.remoteconfig.internal.ConfigGetParameterHandler
import com.google.firebase.remoteconfig.internal.ConfigMetadataClient
import com.google.firebase.remoteconfig.internal.ConfigRealtimeHandler
import com.google.firebase.remoteconfig.internal.ConfigSharedPrefsClient
import com.google.firebase.remoteconfig.internal.rollouts.RolloutsStateSubscriptionsHandler
import java.util.concurrent.Executor

Expand All @@ -41,7 +41,7 @@ fun createRemoteConfig(
defaultConfigsCache: ConfigCacheClient,
fetchHandler: ConfigFetchHandler,
getHandler: ConfigGetParameterHandler,
frcMetadata: ConfigMetadataClient,
frcMetadata: ConfigSharedPrefsClient,
realtimeHandler: ConfigRealtimeHandler,
rolloutsStateSubscriptionsHandler: RolloutsStateSubscriptionsHandler
): FirebaseRemoteConfig {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import com.google.firebase.remoteconfig.createRemoteConfig
import com.google.firebase.remoteconfig.internal.ConfigCacheClient
import com.google.firebase.remoteconfig.internal.ConfigFetchHandler
import com.google.firebase.remoteconfig.internal.ConfigGetParameterHandler
import com.google.firebase.remoteconfig.internal.ConfigMetadataClient
import com.google.firebase.remoteconfig.internal.ConfigRealtimeHandler
import com.google.firebase.remoteconfig.internal.ConfigSharedPrefsClient
import com.google.firebase.remoteconfig.internal.rollouts.RolloutsStateSubscriptionsHandler
import org.junit.After
import org.junit.Before
Expand Down Expand Up @@ -142,7 +142,7 @@ class ConfigTests : BaseTestCase() {
defaultConfigsCache = mock(ConfigCacheClient::class.java),
fetchHandler = mock(ConfigFetchHandler::class.java),
getHandler = mockGetHandler,
frcMetadata = mock(ConfigMetadataClient::class.java),
frcMetadata = mock(ConfigSharedPrefsClient::class.java),
realtimeHandler = mock(ConfigRealtimeHandler::class.java),
rolloutsStateSubscriptionsHandler = mock(RolloutsStateSubscriptionsHandler::class.java)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@
import com.google.firebase.remoteconfig.internal.ConfigContainer;
import com.google.firebase.remoteconfig.internal.ConfigFetchHandler;
import com.google.firebase.remoteconfig.internal.ConfigGetParameterHandler;
import com.google.firebase.remoteconfig.internal.ConfigMetadataClient;
import com.google.firebase.remoteconfig.internal.ConfigRealtimeHandler;
import com.google.firebase.remoteconfig.internal.ConfigSharedPrefsClient;
import com.google.firebase.remoteconfig.internal.rollouts.RolloutsStateSubscriptionsHandler;
import java.util.Date;
import java.util.HashMap;
Expand All @@ -60,7 +60,7 @@ public class FirebaseRemoteConfigIntegrationTest {
@Mock private ConfigCacheClient mockDefaultsCache;
@Mock private ConfigFetchHandler mockFetchHandler;
@Mock private ConfigGetParameterHandler mockGetHandler;
@Mock private ConfigMetadataClient metadataClient;
@Mock private ConfigSharedPrefsClient metadataClient;
@Mock private ConfigRealtimeHandler mockConfigRealtimeHandler;
@Mock private RolloutsStateSubscriptionsHandler mockRolloutsStateSubscriptionHandler;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
import com.google.firebase.remoteconfig.internal.ConfigFetchHandler;
import com.google.firebase.remoteconfig.internal.ConfigFetchHandler.FetchResponse;
import com.google.firebase.remoteconfig.internal.ConfigGetParameterHandler;
import com.google.firebase.remoteconfig.internal.ConfigMetadataClient;
import com.google.firebase.remoteconfig.internal.ConfigRealtimeHandler;
import com.google.firebase.remoteconfig.internal.ConfigSharedPrefsClient;
import com.google.firebase.remoteconfig.internal.DefaultsXmlParser;
import com.google.firebase.remoteconfig.internal.rollouts.RolloutsStateSubscriptionsHandler;
import java.util.ArrayList;
Expand Down Expand Up @@ -160,7 +160,7 @@ public static FirebaseRemoteConfig getInstance(@NonNull FirebaseApp app) {
private final ConfigCacheClient defaultConfigsCache;
private final ConfigFetchHandler fetchHandler;
private final ConfigGetParameterHandler getHandler;
private final ConfigMetadataClient frcMetadata;
private final ConfigSharedPrefsClient frcMetadata;
private final FirebaseInstallationsApi firebaseInstallations;
private final ConfigRealtimeHandler configRealtimeHandler;
private final RolloutsStateSubscriptionsHandler rolloutsStateSubscriptionsHandler;
Expand All @@ -181,7 +181,7 @@ public static FirebaseRemoteConfig getInstance(@NonNull FirebaseApp app) {
ConfigCacheClient defaultConfigsCache,
ConfigFetchHandler fetchHandler,
ConfigGetParameterHandler getHandler,
ConfigMetadataClient frcMetadata,
ConfigSharedPrefsClient frcMetadata,
ConfigRealtimeHandler configRealtimeHandler,
RolloutsStateSubscriptionsHandler rolloutsStateSubscriptionsHandler) {
this.context = context;
Expand Down Expand Up @@ -652,6 +652,28 @@ private Task<Void> setDefaultsWithStringsMapAsync(Map<String, String> defaultsSt
FirebaseExecutors.directExecutor(), (unusedContainer) -> Tasks.forResult(null));
}

/**
* Asynchronously changes the custom signals for this {@link FirebaseRemoteConfig} instance.
*
* <p>The values in {@code customSignals} must be one of the following types:
*
* <ul>
* <li><code>Long</code>
* <li><code>String</code>
* </ul>
*
* @param customSignals Map (key, value) of the custom signals to be set for the app instance
*/
@NonNull
public Task<Void> setCustomSignals(@NonNull Map<String, Object> customSignals) {
return Tasks.call(
executor,
() -> {
frcMetadata.setCustomSignals(customSignals);
return null;
});
}

/**
* Notifies the Firebase A/B Testing SDK about activated experiments.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
import com.google.firebase.remoteconfig.internal.ConfigFetchHandler;
import com.google.firebase.remoteconfig.internal.ConfigFetchHttpClient;
import com.google.firebase.remoteconfig.internal.ConfigGetParameterHandler;
import com.google.firebase.remoteconfig.internal.ConfigMetadataClient;
import com.google.firebase.remoteconfig.internal.ConfigRealtimeHandler;
import com.google.firebase.remoteconfig.internal.ConfigSharedPrefsClient;
import com.google.firebase.remoteconfig.internal.ConfigStorageClient;
import com.google.firebase.remoteconfig.internal.Personalization;
import com.google.firebase.remoteconfig.internal.rollouts.RolloutsStateFactory;
Expand Down Expand Up @@ -166,7 +166,7 @@ public synchronized FirebaseRemoteConfig get(String namespace) {
ConfigCacheClient fetchedCacheClient = getCacheClient(namespace, FETCH_FILE_NAME);
ConfigCacheClient activatedCacheClient = getCacheClient(namespace, ACTIVATE_FILE_NAME);
ConfigCacheClient defaultsCacheClient = getCacheClient(namespace, DEFAULTS_FILE_NAME);
ConfigMetadataClient metadataClient = getMetadataClient(context, appId, namespace);
ConfigSharedPrefsClient metadataClient = getMetadataClient(context, appId, namespace);

ConfigGetParameterHandler getHandler = getGetHandler(activatedCacheClient, defaultsCacheClient);
Personalization personalization =
Expand Down Expand Up @@ -206,7 +206,7 @@ synchronized FirebaseRemoteConfig get(
ConfigCacheClient defaultsClient,
ConfigFetchHandler fetchHandler,
ConfigGetParameterHandler getHandler,
ConfigMetadataClient metadataClient,
ConfigSharedPrefsClient metadataClient,
RolloutsStateSubscriptionsHandler rolloutsStateSubscriptionsHandler) {
if (!frcNamespaceInstances.containsKey(namespace)) {
FirebaseRemoteConfig in =
Expand Down Expand Up @@ -254,20 +254,23 @@ private ConfigCacheClient getCacheClient(String namespace, String configStoreTyp

@VisibleForTesting
ConfigFetchHttpClient getFrcBackendApiClient(
String apiKey, String namespace, ConfigMetadataClient metadataClient) {
String apiKey, String namespace, ConfigSharedPrefsClient metadataClient) {
String appId = firebaseApp.getOptions().getApplicationId();
return new ConfigFetchHttpClient(
context,
appId,
apiKey,
namespace,
/* connectTimeoutInSeconds= */ metadataClient.getFetchTimeoutInSeconds(),
/* readTimeoutInSeconds= */ metadataClient.getFetchTimeoutInSeconds());
/* readTimeoutInSeconds= */ metadataClient.getFetchTimeoutInSeconds(),
/* customSignals= */ metadataClient.getCustomSignals());
}

@VisibleForTesting
synchronized ConfigFetchHandler getFetchHandler(
String namespace, ConfigCacheClient fetchedCacheClient, ConfigMetadataClient metadataClient) {
String namespace,
ConfigCacheClient fetchedCacheClient,
ConfigSharedPrefsClient metadataClient) {
return new ConfigFetchHandler(
firebaseInstallations,
isPrimaryApp(firebaseApp) ? analyticsConnector : () -> null,
Expand All @@ -287,7 +290,7 @@ synchronized ConfigRealtimeHandler getRealtime(
ConfigCacheClient activatedCacheClient,
Context context,
String namespace,
ConfigMetadataClient metadataClient) {
ConfigSharedPrefsClient metadataClient) {
return new ConfigRealtimeHandler(
firebaseApp,
firebaseInstallations,
Expand All @@ -305,13 +308,14 @@ private ConfigGetParameterHandler getGetHandler(
}

@VisibleForTesting
static ConfigMetadataClient getMetadataClient(Context context, String appId, String namespace) {
static ConfigSharedPrefsClient getMetadataClient(
Context context, String appId, String namespace) {
String fileName =
String.format(
"%s_%s_%s_%s",
FIREBASE_REMOTE_CONFIG_FILE_NAME_PREFIX, appId, namespace, PREFERENCES_FILE_NAME);
SharedPreferences preferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE);
return new ConfigMetadataClient(preferences);
return new ConfigSharedPrefsClient(preferences);
}

@Nullable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ public final class RemoteConfigConstants {
RequestFieldKey.PACKAGE_NAME,
RequestFieldKey.SDK_VERSION,
RequestFieldKey.ANALYTICS_USER_PROPERTIES,
RequestFieldKey.FIRST_OPEN_TIME
RequestFieldKey.FIRST_OPEN_TIME,
RequestFieldKey.CUSTOM_SIGNALS
})
@Retention(RetentionPolicy.SOURCE)
public @interface RequestFieldKey {
Expand All @@ -68,6 +69,7 @@ public final class RemoteConfigConstants {
String SDK_VERSION = "sdkVersion";
String ANALYTICS_USER_PROPERTIES = "analyticsUserProperties";
String FIRST_OPEN_TIME = "firstOpenTime";
String CUSTOM_SIGNALS = "customSignals";
}

/** Keys of fields in the Fetch response body from the Firebase Remote Config server. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

package com.google.firebase.remoteconfig.internal;

import static com.google.firebase.remoteconfig.internal.ConfigMetadataClient.LAST_FETCH_TIME_NO_FETCH_YET;
import static com.google.firebase.remoteconfig.internal.ConfigSharedPrefsClient.LAST_FETCH_TIME_NO_FETCH_YET;
import static java.net.HttpURLConnection.HTTP_BAD_GATEWAY;
import static java.net.HttpURLConnection.HTTP_FORBIDDEN;
import static java.net.HttpURLConnection.HTTP_GATEWAY_TIMEOUT;
Expand Down Expand Up @@ -43,7 +43,7 @@
import com.google.firebase.remoteconfig.FirebaseRemoteConfigFetchThrottledException;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigServerException;
import com.google.firebase.remoteconfig.internal.ConfigFetchHandler.FetchResponse.Status;
import com.google.firebase.remoteconfig.internal.ConfigMetadataClient.BackoffMetadata;
import com.google.firebase.remoteconfig.internal.ConfigSharedPrefsClient.BackoffMetadata;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.HttpURLConnection;
Expand Down Expand Up @@ -96,7 +96,7 @@ public class ConfigFetchHandler {
private final Random randomGenerator;
private final ConfigCacheClient fetchedConfigsCache;
private final ConfigFetchHttpClient frcBackendApiClient;
private final ConfigMetadataClient frcMetadata;
private final ConfigSharedPrefsClient frcMetadata;

private final Map<String, String> customHttpHeaders;

Expand All @@ -109,7 +109,7 @@ public ConfigFetchHandler(
Random randomGenerator,
ConfigCacheClient fetchedConfigsCache,
ConfigFetchHttpClient frcBackendApiClient,
ConfigMetadataClient frcMetadata,
ConfigSharedPrefsClient frcMetadata,
Map<String, String> customHttpHeaders) {
this.firebaseInstallations = firebaseInstallations;
this.analyticsConnector = analyticsConnector;
Expand All @@ -124,7 +124,7 @@ public ConfigFetchHandler(

/**
* Calls {@link #fetch(long)} with the {@link
* ConfigMetadataClient#getMinimumFetchIntervalInSeconds()}.
* ConfigSharedPrefsClient#getMinimumFetchIntervalInSeconds()}.
*/
public Task<FetchResponse> fetch() {
return fetch(frcMetadata.getMinimumFetchIntervalInSeconds());
Expand Down Expand Up @@ -228,7 +228,7 @@ public Task<FetchResponse> fetchNowWithTypeAndAttemptNumber(
* currently throttled.
*
* <p>If a fetch request is made to the backend, updates the last fetch status, last successful
* fetch time and {@link BackoffMetadata} in {@link ConfigMetadataClient}.
* fetch time and {@link BackoffMetadata} in {@link ConfigSharedPrefsClient}.
*/
private Task<FetchResponse> fetchIfCacheExpiredAndNotThrottled(
Task<ConfigContainer> cachedFetchConfigsTask,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import static com.google.firebase.remoteconfig.RemoteConfigConstants.RequestFieldKey.APP_ID;
import static com.google.firebase.remoteconfig.RemoteConfigConstants.RequestFieldKey.APP_VERSION;
import static com.google.firebase.remoteconfig.RemoteConfigConstants.RequestFieldKey.COUNTRY_CODE;
import static com.google.firebase.remoteconfig.RemoteConfigConstants.RequestFieldKey.CUSTOM_SIGNALS;
import static com.google.firebase.remoteconfig.RemoteConfigConstants.RequestFieldKey.FIRST_OPEN_TIME;
import static com.google.firebase.remoteconfig.RemoteConfigConstants.RequestFieldKey.INSTANCE_ID;
import static com.google.firebase.remoteconfig.RemoteConfigConstants.RequestFieldKey.INSTANCE_ID_TOKEN;
Expand Down Expand Up @@ -93,6 +94,7 @@ public class ConfigFetchHttpClient {
private final String apiKey;
private final String projectNumber;
private final String namespace;
Map<String, Object> customSignalMap;
private final long connectTimeoutInSeconds;
private final long readTimeoutInSeconds;

Expand All @@ -106,14 +108,16 @@ public ConfigFetchHttpClient(
String apiKey,
String namespace,
long connectTimeoutInSeconds,
long readTimeoutInSeconds) {
long readTimeoutInSeconds,
Map<String, Object> customSignalMap) {
this.context = context;
this.appId = appId;
this.apiKey = apiKey;
this.projectNumber = extractProjectNumberFromAppId(appId);
this.namespace = namespace;
this.connectTimeoutInSeconds = connectTimeoutInSeconds;
this.readTimeoutInSeconds = readTimeoutInSeconds;
this.customSignalMap = customSignalMap;
}

/** Used to verify that the timeout is being set correctly. */
Expand Down Expand Up @@ -347,6 +351,8 @@ private JSONObject createFetchRequestBody(

requestBodyMap.put(ANALYTICS_USER_PROPERTIES, new JSONObject(analyticsUserProperties));

requestBodyMap.put(CUSTOM_SIGNALS, new JSONObject(customSignalMap));

if (firstOpenTime != null) {
requestBodyMap.put(FIRST_OPEN_TIME, convertToISOString(firstOpenTime));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class ConfigRealtimeHandler {
private final ConfigCacheClient activatedCacheClient;
private final Context context;
private final String namespace;
private final ConfigMetadataClient metadataClient;
private final ConfigSharedPrefsClient metadataClient;
private final ScheduledExecutorService scheduledExecutorService;

public ConfigRealtimeHandler(
Expand All @@ -49,7 +49,7 @@ public ConfigRealtimeHandler(
ConfigCacheClient activatedCacheClient,
Context context,
String namespace,
ConfigMetadataClient metadataClient,
ConfigSharedPrefsClient metadataClient,
ScheduledExecutorService scheduledExecutorService) {

this.listeners = new LinkedHashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public class ConfigRealtimeHttpClient {
private final String namespace;
private final Random random;
private final Clock clock;
private final ConfigMetadataClient metadataClient;
private final ConfigSharedPrefsClient metadataClient;

public ConfigRealtimeHttpClient(
FirebaseApp firebaseApp,
Expand All @@ -120,7 +120,7 @@ public ConfigRealtimeHttpClient(
Context context,
String namespace,
Set<ConfigUpdateListener> listeners,
ConfigMetadataClient metadataClient,
ConfigSharedPrefsClient metadataClient,
ScheduledExecutorService scheduledExecutorService) {

this.listeners = listeners;
Expand Down Expand Up @@ -473,7 +473,7 @@ public void beginRealtimeHttpStream() {
return;
}

ConfigMetadataClient.RealtimeBackoffMetadata backoffMetadata =
ConfigSharedPrefsClient.RealtimeBackoffMetadata backoffMetadata =
metadataClient.getRealtimeBackoffMetadata();
Date currentTime = new Date(clock.currentTimeMillis());
if (currentTime.before(backoffMetadata.getBackoffEndTime())) {
Expand Down
Loading
Loading