@@ -60,6 +60,9 @@ DEFINE_FIREBASE_VERSION_STRING(FirebaseRemoteConfig);
6060 X (SetConfigSettingsAsync, " setConfigSettingsAsync" , \
6161 " (Lcom/google/firebase/remoteconfig/FirebaseRemoteConfigSettings;)" \
6262 " Lcom/google/android/gms/tasks/Task;" ), \
63+ X (SetCustomSignalsAsync, " setCustomSignals" , \
64+ " (Lcom/google/firebase/remoteconfig/CustomSignals;)" \
65+ " Lcom/google/android/gms/tasks/Task;" ), \
6366 X (GetLong, " getLong" , " (Ljava/lang/String;)J" ), \
6467 X (GetString, " getString" , " (Ljava/lang/String;)Ljava/lang/String;" ), \
6568 X (GetBoolean, " getBoolean" , " (Ljava/lang/String;)Z" ), \
@@ -150,6 +153,30 @@ METHOD_LOOKUP_DEFINITION(
150153 " com/google/firebase/remoteconfig/FirebaseRemoteConfigSettings$Builder" ,
151154 REMOTE_CONFIG_SETTINGS_BUILDER_METHODS )
152155
156+ // Methods of CustomSignals.Builder
157+ // clang-format off
158+ #define CUSTOM_SIGNALS_BUILDER_METHODS (X ) \
159+ X (Constructor, " <init>" , " ()V" ), \
160+ X (PutString, " put" , \
161+ " (Ljava/lang/String;Ljava/lang/String;)" \
162+ " Lcom/google/firebase/remoteconfig/CustomSignals$Builder;" ), \
163+ X (PutLong, " put" , \
164+ " (Ljava/lang/String;J)" \
165+ " Lcom/google/firebase/remoteconfig/CustomSignals$Builder;" ), \
166+ X (PutDouble, " put" , \
167+ " (Ljava/lang/String;D)" \
168+ " Lcom/google/firebase/remoteconfig/CustomSignals$Builder;" ), \
169+ X (Build, " build" , \
170+ " ()Lcom/google/firebase/remoteconfig/CustomSignals;" )
171+ // clang-format on
172+ METHOD_LOOKUP_DECLARATION (custom_signals_builder,
173+ CUSTOM_SIGNALS_BUILDER_METHODS )
174+ METHOD_LOOKUP_DEFINITION (
175+ custom_signals_builder,
176+ PROGUARD_KEEP_CLASS
177+ " com/google/firebase/remoteconfig/CustomSignals$Builder" ,
178+ CUSTOM_SIGNALS_BUILDER_METHODS )
179+
153180// Methods of FirebaseRemoteConfigFetchThrottledException.
154181// clang-format off
155182#define REMOTE_CONFIG_THROTTLED_EXCEPTION_METHODS (X ) \
@@ -248,6 +275,7 @@ static bool CacheJNIMethodIds(
248275 config_info::CacheMethodIds (env, activity) &&
249276 config_settings::CacheMethodIds (env, activity) &&
250277 config_settings_builder::CacheMethodIds (env, activity) &&
278+ custom_signals_builder::CacheMethodIds (env, activity) &&
251279 throttled_exception::CacheMethodIds (env, activity) &&
252280 config_update::CacheMethodIds (env, activity) &&
253281 config_update_listener_registration::CacheMethodIds (env, activity));
@@ -260,6 +288,7 @@ static void ReleaseClasses(JNIEnv* env) {
260288 config_info::ReleaseClass (env);
261289 config_settings::ReleaseClass (env);
262290 config_settings_builder::ReleaseClass (env);
291+ custom_signals_builder::ReleaseClass (env);
263292 throttled_exception::ReleaseClass (env);
264293 config_update::ReleaseClass (env);
265294 config_update_listener_registration::ReleaseClass (env);
@@ -361,6 +390,88 @@ static jobject ConfigKeyValueVariantArrayToHashMap(
361390 return hash_map;
362391}
363392
393+ // Convert a std::map<std::string, Variant> into a Java CustomSignals object
394+ // using CustomSignals.Builder to populate String, Long, and Double signal
395+ // entries, or null values to clear signals.
396+ static jobject CustomSignalsFromMap (JNIEnv* env,
397+ const std::map<std::string, Variant>& map) {
398+ jobject builder = env->NewObject (custom_signals_builder::GetClass (),
399+ custom_signals_builder::GetMethodId (
400+ custom_signals_builder::kConstructor ));
401+ if (util::CheckAndClearJniExceptions (env) || !builder) return nullptr ;
402+
403+ for (const auto & kv : map) {
404+ jstring key = env->NewStringUTF (kv.first .c_str ());
405+ if (util::CheckAndClearJniExceptions (env) || !key) {
406+ env->DeleteLocalRef (builder);
407+ return nullptr ;
408+ }
409+ jobject result_builder = nullptr ;
410+ if (kv.second .is_null ()) {
411+ result_builder =
412+ env->CallObjectMethod (builder,
413+ custom_signals_builder::GetMethodId (
414+ custom_signals_builder::kPutString ),
415+ key, nullptr );
416+ } else if (kv.second .is_string ()) {
417+ jstring str_val = env->NewStringUTF (kv.second .string_value ());
418+ if (util::CheckAndClearJniExceptions (env) || !str_val) {
419+ env->DeleteLocalRef (key);
420+ env->DeleteLocalRef (builder);
421+ return nullptr ;
422+ }
423+ result_builder =
424+ env->CallObjectMethod (builder,
425+ custom_signals_builder::GetMethodId (
426+ custom_signals_builder::kPutString ),
427+ key, str_val);
428+ env->DeleteLocalRef (str_val);
429+ } else if (kv.second .is_int64 ()) {
430+ result_builder = env->CallObjectMethod (
431+ builder,
432+ custom_signals_builder::GetMethodId (custom_signals_builder::kPutLong ),
433+ key, kv.second .int64_value ());
434+ } else if (kv.second .is_double ()) {
435+ result_builder =
436+ env->CallObjectMethod (builder,
437+ custom_signals_builder::GetMethodId (
438+ custom_signals_builder::kPutDouble ),
439+ key, kv.second .double_value ());
440+ } else {
441+ LogError (
442+ " Remote Config: Invalid Variant type for SetCustomSignals() key %s." ,
443+ kv.first .c_str ());
444+ env->DeleteLocalRef (key);
445+ env->DeleteLocalRef (builder);
446+ return nullptr ;
447+ }
448+
449+ if (util::CheckAndClearJniExceptions (env) || !result_builder) {
450+ if (result_builder) {
451+ env->DeleteLocalRef (result_builder);
452+ }
453+ env->DeleteLocalRef (key);
454+ env->DeleteLocalRef (builder);
455+ return nullptr ;
456+ }
457+
458+ env->DeleteLocalRef (key);
459+ env->DeleteLocalRef (result_builder);
460+ }
461+
462+ jobject custom_signals = env->CallObjectMethod (
463+ builder,
464+ custom_signals_builder::GetMethodId (custom_signals_builder::kBuild ));
465+ if (util::CheckAndClearJniExceptions (env) || !custom_signals) {
466+ if (custom_signals) {
467+ env->DeleteLocalRef (custom_signals);
468+ }
469+ custom_signals = nullptr ;
470+ }
471+ env->DeleteLocalRef (builder);
472+ return custom_signals;
473+ }
474+
364475// Check pending exceptions following a key fetch and log an error if a
365476// failure occurred. If an error occurs this method returns true, false
366477// otherwise.
@@ -959,6 +1070,40 @@ Future<void> RemoteConfigInternal::SetConfigSettingsLastResult() {
9591070 future_impl_.LastResult (kRemoteConfigFnSetConfigSettings ));
9601071}
9611072
1073+ Future<void > RemoteConfigInternal::SetCustomSignals (
1074+ const std::map<std::string, Variant>& custom_signals) {
1075+ const auto handle =
1076+ future_impl_.SafeAlloc <void >(kRemoteConfigFnSetCustomSignals );
1077+ JNIEnv* env = app_.GetJNIEnv ();
1078+ jobject j_custom_signals = CustomSignalsFromMap (env, custom_signals);
1079+ if (!j_custom_signals) {
1080+ future_impl_.Complete (handle, kFutureStatusFailure ,
1081+ " SetCustomSignals native function fails" );
1082+ return MakeFuture<void >(&future_impl_, handle);
1083+ }
1084+ jobject task = env->CallObjectMethod (
1085+ internal_obj_, config::GetMethodId (config::kSetCustomSignalsAsync ),
1086+ j_custom_signals);
1087+ if (util::CheckAndClearJniExceptions (env)) {
1088+ task = nullptr ;
1089+ future_impl_.Complete (handle, kFutureStatusFailure ,
1090+ " SetCustomSignals native function fails" );
1091+ } else {
1092+ auto data_handle = new RCDataHandle<void >(&future_impl_, handle, this );
1093+ util::RegisterCallbackOnTask (env, task, CompleteVoidCallback,
1094+ reinterpret_cast <void *>(data_handle),
1095+ jni_task_id_.c_str ());
1096+ }
1097+ env->DeleteLocalRef (task);
1098+ env->DeleteLocalRef (j_custom_signals);
1099+ return MakeFuture<void >(&future_impl_, handle);
1100+ }
1101+
1102+ Future<void > RemoteConfigInternal::SetCustomSignalsLastResult () {
1103+ return static_cast <const Future<void >&>(
1104+ future_impl_.LastResult (kRemoteConfigFnSetCustomSignals ));
1105+ }
1106+
9621107ConfigSettings RemoteConfigInternal::GetConfigSettings () {
9631108 ConfigSettings settings;
9641109 JNIEnv* env = app_.GetJNIEnv ();
0 commit comments