Skip to content

Commit f84caa0

Browse files
authored
Merge 8ddab84 into a06d206
2 parents a06d206 + 8ddab84 commit f84caa0

File tree

10 files changed

+378
-4
lines changed

10 files changed

+378
-4
lines changed

analytics/integration_test/src/integration_test.cc

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,4 +341,70 @@ TEST_F(FirebaseAnalyticsTest, TestSetConsent) {
341341
did_test_setconsent_ = true;
342342
}
343343

344+
TEST_F(FirebaseAnalyticsTest, TestDefaultEventParametersUsage) {
345+
LogInfo(
346+
"Testing SetDefaultEventParameters with initial values, then updating "
347+
"with Null.");
348+
349+
std::map<std::string, firebase::Variant> initial_defaults;
350+
initial_defaults["initial_key"] = "initial_value";
351+
initial_defaults["key_to_be_nulled"] = "text_before_null";
352+
initial_defaults["numeric_default"] = 12345;
353+
354+
LogInfo("Setting initial default event parameters.");
355+
firebase::analytics::SetDefaultEventParameters(initial_defaults);
356+
// Log an event that would pick up these defaults.
357+
firebase::analytics::LogEvent("event_with_initial_defaults");
358+
LogInfo("Logged event_with_initial_defaults.");
359+
ProcessEvents(
360+
500); // Short pause for event logging, if it matters for backend.
361+
362+
std::map<std::string, firebase::Variant> updated_defaults;
363+
updated_defaults["key_to_be_nulled"] = firebase::Variant::Null();
364+
updated_defaults["another_key"] = "another_value";
365+
// "initial_key" should persist if not overwritten.
366+
// "numeric_default" should persist.
367+
368+
LogInfo(
369+
"Updating default event parameters, setting key_to_be_nulled to Null.");
370+
firebase::analytics::SetDefaultEventParameters(updated_defaults);
371+
// Log an event that would pick up the updated defaults.
372+
firebase::analytics::LogEvent("event_after_nulling_and_adding");
373+
LogInfo("Logged event_after_nulling_and_adding.");
374+
ProcessEvents(500);
375+
376+
// For this C++ SDK integration test, we primarily ensure API calls complete.
377+
// Actual parameter presence on logged events would be verified by
378+
// backend/native tests.
379+
LogInfo(
380+
"TestDefaultEventParametersUsage completed. Calls were made "
381+
"successfully.");
382+
}
383+
384+
TEST_F(FirebaseAnalyticsTest, TestClearDefaultEventParametersFunctionality) {
385+
LogInfo("Testing ClearDefaultEventParameters.");
386+
387+
std::map<std::string, firebase::Variant> defaults_to_clear;
388+
defaults_to_clear["default_one"] = "will_be_cleared";
389+
defaults_to_clear["default_two"] = 9876;
390+
391+
LogInfo("Setting default parameters before clearing.");
392+
firebase::analytics::SetDefaultEventParameters(defaults_to_clear);
393+
// Log an event that would pick up these defaults.
394+
firebase::analytics::LogEvent("event_before_global_clear");
395+
LogInfo("Logged event_before_global_clear.");
396+
ProcessEvents(500);
397+
398+
LogInfo("Calling ClearDefaultEventParameters.");
399+
firebase::analytics::ClearDefaultEventParameters();
400+
// Log an event that should not have the previous defaults.
401+
firebase::analytics::LogEvent("event_after_global_clear");
402+
LogInfo("Logged event_after_global_clear.");
403+
ProcessEvents(500);
404+
405+
LogInfo(
406+
"TestClearDefaultEventParametersFunctionality completed. Call was made "
407+
"successfully.");
408+
}
409+
344410
} // namespace firebase_testapp_automated

analytics/src/analytics_android.cc

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ static const ::firebase::App* g_app = nullptr;
5858
"()Lcom/google/android/gms/tasks/Task;"), \
5959
X(GetSessionId, "getSessionId", \
6060
"()Lcom/google/android/gms/tasks/Task;"), \
61+
X(SetDefaultEventParameters, "setDefaultEventParameters", \
62+
"(Landroid/os/Bundle;)V", util::kMethodTypeInstance), \
6163
X(GetInstance, "getInstance", "(Landroid/content/Context;)" \
6264
"Lcom/google/firebase/analytics/FirebaseAnalytics;", \
6365
firebase::util::kMethodTypeStatic)
@@ -512,7 +514,8 @@ void LogEvent(const char* name, const Parameter* parameters,
512514
LogError(
513515
"LogEvent(%s): %s is not a valid parameter value type. "
514516
"No event was logged.",
515-
parameter.name, Variant::TypeName(parameter.value.type()));
517+
parameter.name,
518+
firebase::Variant::TypeName(parameter.value.type()));
516519
}
517520
}
518521
});
@@ -609,6 +612,105 @@ void ResetAnalyticsData() {
609612
util::CheckAndClearJniExceptions(env);
610613
}
611614

615+
void SetDefaultEventParameters(
616+
const std::map<std::string, firebase::Variant>& default_parameters) {
617+
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
618+
JNIEnv* env = g_app->GetJNIEnv();
619+
if (!env) return;
620+
621+
jobject bundle =
622+
env->NewObject(util::bundle::GetClass(),
623+
util::bundle::GetMethodId(util::bundle::kConstructor));
624+
if (util::CheckAndClearJniExceptions(env) || !bundle) {
625+
LogError("Failed to create Bundle for SetDefaultEventParameters.");
626+
if (bundle) env->DeleteLocalRef(bundle);
627+
return;
628+
}
629+
630+
for (const auto& pair : default_parameters) {
631+
const Variant& value = pair.second;
632+
const char* key_cstr = pair.first.c_str();
633+
634+
if (value.is_null()) {
635+
jstring key_jstring = env->NewStringUTF(key_cstr);
636+
if (util::CheckAndClearJniExceptions(env) || !key_jstring) {
637+
LogError(
638+
"SetDefaultEventParameters: Failed to create jstring for null "
639+
"value key: %s",
640+
key_cstr);
641+
if (key_jstring) env->DeleteLocalRef(key_jstring);
642+
continue;
643+
}
644+
env->CallVoidMethod(bundle,
645+
util::bundle::GetMethodId(util::bundle::kPutString),
646+
key_jstring, nullptr);
647+
if (util::CheckAndClearJniExceptions(env)) {
648+
LogError(
649+
"SetDefaultEventParameters: Failed to put null string for key: %s",
650+
key_cstr);
651+
}
652+
env->DeleteLocalRef(key_jstring);
653+
} else if (value.is_string() || value.is_int64() || value.is_double() ||
654+
value.is_bool()) {
655+
// AddVariantToBundle handles these types and their JNI conversions.
656+
// It also logs if an individual AddToBundle within it fails or if a type
657+
// is unsupported by it.
658+
if (!AddVariantToBundle(env, bundle, key_cstr, value)) {
659+
// This specific log gives context that the failure happened during
660+
// SetDefaultEventParameters for a type that was expected to be
661+
// supported by AddVariantToBundle.
662+
LogError(
663+
"SetDefaultEventParameters: Failed to add parameter for key '%s' "
664+
"with supported type '%s'. This might indicate a JNI issue during "
665+
"conversion.",
666+
key_cstr, Variant::TypeName(value.type()));
667+
}
668+
} else if (value.is_vector() || value.is_map()) {
669+
LogError(
670+
"SetDefaultEventParameters: Value for key '%s' has type '%s' which "
671+
"is not supported for default event parameters. Only string, int64, "
672+
"double, bool, and null are supported. Skipping.",
673+
key_cstr, Variant::TypeName(value.type()));
674+
} else {
675+
// This case handles other fundamental Variant types that are not scalars
676+
// and not vector/map.
677+
LogError(
678+
"SetDefaultEventParameters: Value for key '%s' has an unexpected and "
679+
"unsupported type '%s'. Skipping.",
680+
key_cstr, Variant::TypeName(value.type()));
681+
}
682+
}
683+
684+
env->CallVoidMethod(
685+
g_analytics_class_instance,
686+
analytics::GetMethodId(analytics::kSetDefaultEventParameters), bundle);
687+
if (util::CheckAndClearJniExceptions(env)) {
688+
LogError("Failed to call setDefaultEventParameters on Java instance.");
689+
}
690+
691+
env->DeleteLocalRef(bundle);
692+
}
693+
694+
void ClearDefaultEventParameters() {
695+
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
696+
JNIEnv* env = g_app->GetJNIEnv();
697+
if (!env) return;
698+
699+
// Calling with nullptr bundle should clear the parameters.
700+
env->CallVoidMethod(
701+
g_analytics_class_instance,
702+
analytics::GetMethodId(analytics::kSetDefaultEventParameters), nullptr);
703+
if (util::CheckAndClearJniExceptions(env)) {
704+
// This might happen if the method isn't available on older SDKs,
705+
// or if some other JNI error occurs.
706+
LogError(
707+
"Failed to call setDefaultEventParameters(null) on Java instance. "
708+
"This may indicate the method is not available on this Android SDK "
709+
"version "
710+
"or another JNI error occurred.");
711+
}
712+
}
713+
612714
Future<std::string> GetAnalyticsInstanceId() {
613715
FIREBASE_ASSERT_RETURN(GetAnalyticsInstanceIdLastResult(),
614716
internal::IsInitialized());

analytics/src/analytics_ios.mm

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ void LogEvent(const char* name, const Parameter* parameters, size_t number_of_pa
306306
// A Variant type that couldn't be handled was passed in.
307307
LogError("LogEvent(%s): %s is not a valid parameter value type. "
308308
"No event was logged.",
309-
parameter.name, Variant::TypeName(parameter.value.type()));
309+
parameter.name, firebase::Variant::TypeName(parameter.value.type()));
310310
}
311311
}
312312
[FIRAnalytics logEventWithName:@(name) parameters:parameters_dict];
@@ -373,6 +373,44 @@ void SetSessionTimeoutDuration(int64_t milliseconds) {
373373
setSessionTimeoutInterval:static_cast<NSTimeInterval>(milliseconds) / kMillisecondsPerSecond];
374374
}
375375

376+
void SetDefaultEventParameters(const std::map<std::string, firebase::Variant>& default_parameters) {
377+
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
378+
NSMutableDictionary* ns_default_parameters =
379+
[[NSMutableDictionary alloc] initWithCapacity:default_parameters.size()];
380+
for (const auto& pair : default_parameters) {
381+
NSString* key = SafeString(pair.first.c_str());
382+
const Variant& value = pair.second;
383+
384+
if (value.is_null()) {
385+
[ns_default_parameters setObject:[NSNull null] forKey:key];
386+
} else if (value.is_int64()) {
387+
[ns_default_parameters setObject:[NSNumber numberWithLongLong:value.int64_value()]
388+
forKey:key];
389+
} else if (value.is_double()) {
390+
[ns_default_parameters setObject:[NSNumber numberWithDouble:value.double_value()] forKey:key];
391+
} else if (value.is_string()) {
392+
[ns_default_parameters setObject:SafeString(value.string_value()) forKey:key];
393+
} else if (value.is_bool()) {
394+
[ns_default_parameters setObject:[NSNumber numberWithBool:value.bool_value()] forKey:key];
395+
} else if (value.is_vector() || value.is_map()) {
396+
LogError("SetDefaultEventParameters: Value for key '%s' has type '%s' which is not supported "
397+
"for default event parameters. Only string, int64, double, bool, and null are "
398+
"supported. Skipping.",
399+
pair.first.c_str(), Variant::TypeName(value.type()));
400+
} else {
401+
LogError("SetDefaultEventParameters: Value for key '%s' has an unexpected type '%s' which is "
402+
"not supported. Skipping.",
403+
pair.first.c_str(), Variant::TypeName(value.type()));
404+
}
405+
}
406+
[FIRAnalytics setDefaultEventParameters:ns_default_parameters];
407+
}
408+
409+
void ClearDefaultEventParameters() {
410+
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
411+
[FIRAnalytics setDefaultEventParameters:nil];
412+
}
413+
376414
void ResetAnalyticsData() {
377415
MutexLock lock(g_mutex);
378416
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());

analytics/src/analytics_stub.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,17 @@ void SetSessionTimeoutDuration(int64_t /*milliseconds*/) {
142142
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
143143
}
144144

145+
void SetDefaultEventParameters(
146+
const std::map<std::string, firebase::Variant>& /*default_parameters*/) {
147+
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
148+
// This is a stub implementation. No operation needed.
149+
}
150+
151+
void ClearDefaultEventParameters() {
152+
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
153+
// This is a stub implementation. No operation needed.
154+
}
155+
145156
void ResetAnalyticsData() {
146157
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
147158
g_fake_instance_id++;

analytics/src/include/firebase/analytics.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ struct Parameter {
142142
/// @param parameter_name Name of the parameter (see Parameter::name).
143143
/// @param parameter_value Value for the parameter. Variants can
144144
/// hold numbers and strings.
145-
Parameter(const char* parameter_name, Variant parameter_value)
145+
Parameter(const char* parameter_name, firebase::Variant parameter_value)
146146
: name(parameter_name) {
147147
value = parameter_value;
148148
}
@@ -245,7 +245,7 @@ struct Parameter {
245245
///
246246
/// See firebase::Variant for usage information.
247247
/// @note String values can be up to 100 characters long.
248-
Variant value;
248+
firebase::Variant value;
249249
#endif // SWIG
250250
};
251251

@@ -558,6 +558,23 @@ void SetSessionTimeoutDuration(int64_t milliseconds);
558558
/// instance id.
559559
void ResetAnalyticsData();
560560

561+
/// @brief Sets the default event parameters.
562+
///
563+
/// These parameters will be automatically logged with all calls to `LogEvent`.
564+
/// Default parameters are overridden by parameters supplied to the `LogEvent`
565+
/// method.
566+
///
567+
/// When a value in the `default_parameters` map is
568+
/// `firebase::Variant::Null()`, it signifies that the default parameter for
569+
/// that specific key should be cleared.
570+
///
571+
/// @param[in] default_parameters A map of parameter names to Variant values.
572+
void SetDefaultEventParameters(
573+
const std::map<std::string, firebase::Variant>& default_parameters);
574+
575+
/// @brief Clears all default event parameters.
576+
void ClearDefaultEventParameters();
577+
561578
/// Get the instance ID from the analytics service.
562579
///
563580
/// @note This is *not* the same ID as the ID returned by

analytics/src_ios/fake/FIRAnalytics.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,6 @@
3737

3838
+ (void)resetAnalyticsData;
3939

40+
+ (void)setDefaultEventParameters:(nullable NSDictionary<NSString *, id> *)parameters;
41+
4042
@end

analytics/src_ios/fake/FIRAnalytics.mm

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
@implementation FIRAnalytics
2222

2323
+ (NSString *)stringForValue:(id)value {
24+
if (value == [NSNull null]) {
25+
return @"<NSNull>";
26+
}
2427
return [NSString stringWithFormat:@"%@", value];
2528
}
2629

@@ -94,4 +97,14 @@ + (void)resetAnalyticsData {
9497
FakeReporter->AddReport("+[FIRAnalytics resetAnalyticsData]", {});
9598
}
9699

100+
+ (void)setDefaultEventParameters:(nullable NSDictionary<NSString *, id> *)parameters {
101+
if (parameters == nil) {
102+
FakeReporter->AddReport("+[FIRAnalytics setDefaultEventParameters:]", {"nil"});
103+
} else {
104+
NSString *parameterString = [self stringForParameters:parameters];
105+
FakeReporter->AddReport("+[FIRAnalytics setDefaultEventParameters:]",
106+
{ [parameterString UTF8String] });
107+
}
108+
}
109+
97110
@end

analytics/src_java/fake/com/google/firebase/analytics/FirebaseAnalytics.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,31 @@ public void setSessionTimeoutDuration(long milliseconds) {
7979
FakeReporter.addReport(
8080
"FirebaseAnalytics.setSessionTimeoutDuration", Long.toString(milliseconds));
8181
}
82+
83+
public void setDefaultEventParameters(Bundle bundle) {
84+
if (bundle == null) {
85+
FakeReporter.addReport("FirebaseAnalytics.setDefaultEventParameters", "null");
86+
} else {
87+
StringBuilder paramsString = new StringBuilder();
88+
// Sort keys for predictable ordering.
89+
for (String key : new TreeSet<>(bundle.keySet())) {
90+
paramsString.append(key);
91+
paramsString.append("=");
92+
Object value = bundle.get(key); // Get as Object first
93+
if (value == null) {
94+
// This case handles when bundle.putString(key, null) was called.
95+
paramsString.append("<null_string_value>");
96+
} else {
97+
paramsString.append(value.toString());
98+
}
99+
paramsString.append(",");
100+
}
101+
// Remove trailing comma if paramsString is not empty
102+
if (paramsString.length() > 0) {
103+
paramsString.setLength(paramsString.length() - 1);
104+
}
105+
FakeReporter.addReport(
106+
"FirebaseAnalytics.setDefaultEventParameters", paramsString.toString());
107+
}
108+
}
82109
}

0 commit comments

Comments
 (0)