Skip to content

Commit 9723100

Browse files
Internal updates (#1349)
* Internal updates
1 parent 99b39b0 commit 9723100

File tree

14 files changed

+510
-12
lines changed

14 files changed

+510
-12
lines changed

app/src/util_android.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -491,13 +491,14 @@ METHOD_LOOKUP_DECLARATION(activity, ACTIVITY_METHODS)
491491
// Used to setup the cache of Bundle class method IDs to reduce time spent
492492
// looking up methods by string.
493493
// clang-format off
494-
#define BUNDLE_METHODS(X) \
495-
X(Constructor, "<init>", "()V"), \
496-
X(GetString, "getString", "(Ljava/lang/String;)Ljava/lang/String;"), \
497-
X(KeySet, "keySet", "()Ljava/util/Set;"), \
498-
X(PutFloat, "putFloat", "(Ljava/lang/String;F)V"), \
499-
X(PutLong, "putLong", "(Ljava/lang/String;J)V"), \
500-
X(PutString, "putString", "(Ljava/lang/String;Ljava/lang/String;)V")
494+
#define BUNDLE_METHODS(X) \
495+
X(Constructor, "<init>", "()V"), \
496+
X(GetString, "getString", "(Ljava/lang/String;)Ljava/lang/String;"), \
497+
X(KeySet, "keySet", "()Ljava/util/Set;"), \
498+
X(PutFloat, "putFloat", "(Ljava/lang/String;F)V"), \
499+
X(PutLong, "putLong", "(Ljava/lang/String;J)V"), \
500+
X(PutString, "putString", "(Ljava/lang/String;Ljava/lang/String;)V"), \
501+
X(PutBundle, "putBundle", "(Ljava/lang/String;Landroid/os/Bundle;)V")
501502
// clang-format on
502503
METHOD_LOOKUP_DECLARATION(bundle, BUNDLE_METHODS)
503504

@@ -1125,6 +1126,7 @@ jint AttachCurrentThread(JavaVM* java_vm, JNIEnv** env);
11251126
// firebase::App, either the default App (if it exists) or any valid
11261127
// App. If there is no instantiated App, returns nullptr.
11271128
JNIEnv* GetJNIEnvFromApp();
1129+
11281130
} // namespace util
11291131
// NOLINTNEXTLINE - allow namespace overridden
11301132
} // namespace firebase

gma/integration_test/src/integration_test.cc

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ class FirebaseGmaTest : public FirebaseTest {
159159

160160
protected:
161161
firebase::gma::AdRequest GetAdRequest();
162+
firebase::Variant GetVariantMap();
162163

163164
static firebase::App* shared_app_;
164165
};
@@ -285,6 +286,20 @@ firebase::gma::AdRequest FirebaseGmaTest::GetAdRequest() {
285286
return request;
286287
}
287288

289+
firebase::Variant FirebaseGmaTest::GetVariantMap() {
290+
firebase::Variant in_key = firebase::Variant::FromMutableString("inner_key");
291+
firebase::Variant in_val = firebase::Variant::FromMutableString("inner_val");
292+
firebase::Variant out_key = firebase::Variant::FromMutableString("outer_key");
293+
294+
firebase::Variant out_val = firebase::Variant::EmptyMap();
295+
out_val.map()[in_key] = in_val;
296+
297+
firebase::Variant variant_map = firebase::Variant::EmptyMap();
298+
variant_map.map()[out_key] = out_val;
299+
300+
return variant_map;
301+
}
302+
288303
FirebaseGmaUITest::FirebaseGmaUITest() {}
289304

290305
FirebaseGmaUITest::~FirebaseGmaUITest() {}
@@ -399,6 +414,8 @@ TEST_F(FirebaseGmaTest, TestSetAppKeyEnabled) {
399414

400415
TEST_F(FirebaseGmaTest, TestGetAdRequest) { GetAdRequest(); }
401416

417+
TEST_F(FirebaseGmaTest, TestGetVariantMap) { GetVariantMap(); }
418+
402419
TEST_F(FirebaseGmaTest, TestGetAdRequestValues) {
403420
SKIP_TEST_ON_DESKTOP;
404421

@@ -2058,6 +2075,80 @@ TEST_F(FirebaseGmaTest, TestNativeAdLoadEmptyRequest) {
20582075
delete native_ad;
20592076
}
20602077

2078+
TEST_F(FirebaseGmaTest, TestNativeRecordImpression) {
2079+
SKIP_TEST_ON_DESKTOP;
2080+
SKIP_TEST_ON_SIMULATOR;
2081+
2082+
firebase::gma::NativeAd* native_ad = new firebase::gma::NativeAd();
2083+
2084+
WaitForCompletion(native_ad->Initialize(app_framework::GetWindowContext()),
2085+
"Initialize");
2086+
2087+
// When the NativeAd is initialized, load an ad.
2088+
firebase::Future<firebase::gma::AdResult> load_ad_future =
2089+
native_ad->LoadAd(kNativeAdUnit, GetAdRequest());
2090+
2091+
WaitForCompletion(load_ad_future, "LoadAd");
2092+
const firebase::gma::AdResult* result_ptr = load_ad_future.result();
2093+
ASSERT_NE(result_ptr, nullptr);
2094+
EXPECT_TRUE(result_ptr->is_successful());
2095+
2096+
load_ad_future.Release();
2097+
2098+
firebase::Variant impression_payload = GetVariantMap();
2099+
2100+
#if defined(ANDROID)
2101+
// Android doesn't have a return type for this API.
2102+
WaitForCompletion(native_ad->RecordImpression(impression_payload),
2103+
"RecordImpression");
2104+
#else // iOS
2105+
// Test Ad unit IDs are not allowlisted to record impression and the request
2106+
// is expected to be rejected by the server. iOS returns the failure.
2107+
WaitForCompletion(native_ad->RecordImpression(impression_payload),
2108+
"RecordImpression",
2109+
firebase::gma::kAdErrorCodeInvalidRequest);
2110+
#endif
2111+
2112+
firebase::Variant str_variant = firebase::Variant::FromMutableString("test");
2113+
WaitForCompletion(native_ad->RecordImpression(str_variant),
2114+
"RecordImpression 2",
2115+
firebase::gma::kAdErrorCodeInvalidArgument);
2116+
2117+
delete native_ad;
2118+
}
2119+
2120+
TEST_F(FirebaseGmaTest, TestNativePerformClick) {
2121+
SKIP_TEST_ON_DESKTOP;
2122+
SKIP_TEST_ON_SIMULATOR;
2123+
2124+
firebase::gma::NativeAd* native_ad = new firebase::gma::NativeAd();
2125+
2126+
WaitForCompletion(native_ad->Initialize(app_framework::GetWindowContext()),
2127+
"Initialize");
2128+
2129+
// When the NativeAd is initialized, load an ad.
2130+
firebase::Future<firebase::gma::AdResult> load_ad_future =
2131+
native_ad->LoadAd(kNativeAdUnit, GetAdRequest());
2132+
2133+
WaitForCompletion(load_ad_future, "LoadAd");
2134+
const firebase::gma::AdResult* result_ptr = load_ad_future.result();
2135+
ASSERT_NE(result_ptr, nullptr);
2136+
EXPECT_TRUE(result_ptr->is_successful());
2137+
2138+
load_ad_future.Release();
2139+
2140+
firebase::Variant click_payload = GetVariantMap();
2141+
2142+
// Android and iOS doesn't have a return type for this API.
2143+
WaitForCompletion(native_ad->PerformClick(click_payload), "PerformClick");
2144+
2145+
firebase::Variant str_variant = firebase::Variant::FromMutableString("test");
2146+
WaitForCompletion(native_ad->PerformClick(str_variant), "PerformClick 2",
2147+
firebase::gma::kAdErrorCodeInvalidArgument);
2148+
2149+
delete native_ad;
2150+
}
2151+
20612152
TEST_F(FirebaseGmaTest, TestNativeAdErrorNotInitialized) {
20622153
SKIP_TEST_ON_DESKTOP;
20632154

@@ -2067,6 +2158,12 @@ TEST_F(FirebaseGmaTest, TestNativeAdErrorNotInitialized) {
20672158
WaitForCompletion(native_ad->LoadAd(kNativeAdUnit, request), "LoadAd",
20682159
firebase::gma::kAdErrorCodeUninitialized);
20692160

2161+
firebase::Variant variant = firebase::Variant::EmptyMap();
2162+
WaitForCompletion(native_ad->RecordImpression(variant), "RecordImpression",
2163+
firebase::gma::kAdErrorCodeUninitialized);
2164+
WaitForCompletion(native_ad->PerformClick(variant), "PerformClick",
2165+
firebase::gma::kAdErrorCodeUninitialized);
2166+
20702167
delete native_ad;
20712168
}
20722169

gma/src/android/native_ad_internal_android.cc

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,133 @@ Future<AdResult> NativeAdInternalAndroid::LoadAd(const char* ad_unit_id,
138138
return future;
139139
}
140140

141+
Future<void> NativeAdInternalAndroid::RecordImpression(
142+
const Variant& impression_data) {
143+
firebase::MutexLock lock(mutex_);
144+
145+
if (!initialized_) {
146+
return CreateAndCompleteFuture(kNativeAdFnRecordImpression,
147+
kAdErrorCodeUninitialized,
148+
kAdUninitializedErrorMessage, &future_data_);
149+
}
150+
151+
jobject impression_bundle = variantmap_to_bundle(impression_data);
152+
153+
if (impression_bundle == nullptr) {
154+
return CreateAndCompleteFuture(
155+
kNativeAdFnRecordImpression, kAdErrorCodeInvalidArgument,
156+
kUnsupportedVariantTypeErrorMessage, &future_data_);
157+
}
158+
159+
JNIEnv* env = ::firebase::gma::GetJNI();
160+
FIREBASE_ASSERT(env);
161+
162+
FutureCallbackData<void>* callback_data =
163+
CreateVoidFutureCallbackData(kNativeAdFnRecordImpression, &future_data_);
164+
Future<void> future =
165+
MakeFuture(&future_data_.future_impl, callback_data->future_handle);
166+
env->CallVoidMethod(
167+
helper_,
168+
native_ad_helper::GetMethodId(native_ad_helper::kRecordImpression),
169+
reinterpret_cast<jlong>(callback_data), impression_bundle);
170+
171+
util::CheckAndClearJniExceptions(env);
172+
173+
return future;
174+
}
175+
176+
Future<void> NativeAdInternalAndroid::PerformClick(const Variant& click_data) {
177+
firebase::MutexLock lock(mutex_);
178+
179+
if (!initialized_) {
180+
return CreateAndCompleteFuture(kNativeAdFnPerformClick,
181+
kAdErrorCodeUninitialized,
182+
kAdUninitializedErrorMessage, &future_data_);
183+
}
184+
185+
jobject click_bundle = variantmap_to_bundle(click_data);
186+
187+
if (click_bundle == nullptr) {
188+
return CreateAndCompleteFuture(
189+
kNativeAdFnPerformClick, kAdErrorCodeInvalidArgument,
190+
kUnsupportedVariantTypeErrorMessage, &future_data_);
191+
}
192+
193+
JNIEnv* env = ::firebase::gma::GetJNI();
194+
FIREBASE_ASSERT(env);
195+
196+
FutureCallbackData<void>* callback_data =
197+
CreateVoidFutureCallbackData(kNativeAdFnPerformClick, &future_data_);
198+
Future<void> future =
199+
MakeFuture(&future_data_.future_impl, callback_data->future_handle);
200+
env->CallVoidMethod(
201+
helper_, native_ad_helper::GetMethodId(native_ad_helper::kPerformClick),
202+
reinterpret_cast<jlong>(callback_data), click_bundle);
203+
204+
util::CheckAndClearJniExceptions(env);
205+
206+
return future;
207+
}
208+
209+
jobject NativeAdInternalAndroid::variantmap_to_bundle(
210+
const Variant& variant_data) {
211+
if (!variant_data.is_map()) {
212+
return nullptr;
213+
}
214+
215+
JNIEnv* env = ::firebase::gma::GetJNI();
216+
FIREBASE_ASSERT(env);
217+
218+
jobject variant_bundle =
219+
env->NewObject(util::bundle::GetClass(),
220+
util::bundle::GetMethodId(util::bundle::kConstructor));
221+
FIREBASE_ASSERT(variant_bundle);
222+
223+
for (const auto& kvp : variant_data.map()) {
224+
const Variant& key = kvp.first;
225+
const Variant& value = kvp.second;
226+
227+
if (!key.is_string()) {
228+
return nullptr;
229+
}
230+
jstring key_str = env->NewStringUTF(key.string_value());
231+
util::CheckAndClearJniExceptions(env);
232+
233+
if (value.is_int64()) {
234+
jlong val_long = (jlong)value.int64_value();
235+
env->CallVoidMethod(variant_bundle,
236+
util::bundle::GetMethodId(util::bundle::kPutLong),
237+
key_str, val_long);
238+
} else if (value.is_double()) {
239+
jfloat val_float = (jfloat)value.double_value();
240+
env->CallVoidMethod(variant_bundle,
241+
util::bundle::GetMethodId(util::bundle::kPutFloat),
242+
key_str, val_float);
243+
} else if (value.is_string()) {
244+
jstring val_str = env->NewStringUTF(value.string_value());
245+
env->CallVoidMethod(variant_bundle,
246+
util::bundle::GetMethodId(util::bundle::kPutString),
247+
key_str, val_str);
248+
env->DeleteLocalRef(val_str);
249+
} else if (value.is_map()) {
250+
jobject val_bundle = variantmap_to_bundle(value);
251+
env->CallVoidMethod(variant_bundle,
252+
util::bundle::GetMethodId(util::bundle::kPutBundle),
253+
key_str, val_bundle);
254+
env->DeleteLocalRef(val_bundle);
255+
} else {
256+
// Unsupported value type.
257+
env->DeleteLocalRef(key_str);
258+
return nullptr;
259+
}
260+
261+
util::CheckAndClearJniExceptions(env);
262+
env->DeleteLocalRef(key_str);
263+
}
264+
265+
return variant_bundle;
266+
}
267+
141268
} // namespace internal
142269
} // namespace gma
143270
} // namespace firebase

gma/src/android/native_ad_internal_android.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ namespace gma {
2828
// time spent looking up methods by string.
2929
// clang-format off
3030
#define NATIVEADHELPER_METHODS(X) \
31-
X(Constructor, "<init>", "(J)V"), \
32-
X(Initialize, "initialize", "(JLandroid/app/Activity;)V"), \
33-
X(LoadAd, "loadAd", \
34-
"(JLjava/lang/String;Lcom/google/android/gms/ads/AdRequest;)V"), \
31+
X(Constructor, "<init>", "(J)V"), \
32+
X(Initialize, "initialize", "(JLandroid/app/Activity;)V"), \
33+
X(LoadAd, "loadAd", \
34+
"(JLjava/lang/String;Lcom/google/android/gms/ads/AdRequest;)V"), \
35+
X(RecordImpression, "recordImpression", "(JLandroid/os/Bundle;)V"), \
36+
X(PerformClick, "performClick", "(JLandroid/os/Bundle;)V"), \
3537
X(Disconnect, "disconnect", "()V")
3638
// clang-format on
3739

@@ -48,6 +50,9 @@ class NativeAdInternalAndroid : public NativeAdInternal {
4850
Future<AdResult> LoadAd(const char* ad_unit_id,
4951
const AdRequest& request) override;
5052
bool is_initialized() const override { return initialized_; }
53+
Future<void> RecordImpression(const Variant& impression_data) override;
54+
Future<void> PerformClick(const Variant& click_data) override;
55+
jobject variantmap_to_bundle(const Variant& variant_data);
5156

5257
private:
5358
// Reference to the Java helper object used to interact with the Mobile Ads

gma/src/common/gma_common.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ const char* kAdLoadInProgressErrorMessage = "Ad is currently loading.";
6767
const char* kAdUninitializedErrorMessage = "Ad has not been fully initialized.";
6868
const char* kImageUrlMalformedErrorMessage =
6969
"Image URL is malformed or missing.";
70+
const char* kUnsupportedVariantTypeErrorMessage = "Unsupported variant type.";
71+
const char* kRecordImpressionFailureErrorMessage =
72+
"Failed to record impression.";
7073

7174
// GmaInternal
7275
void GmaInternal::CompleteLoadAdFutureSuccess(

gma/src/common/gma_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ extern const char* kAdCouldNotParseAdRequestErrorMessage;
3939
extern const char* kAdLoadInProgressErrorMessage;
4040
extern const char* kAdUninitializedErrorMessage;
4141
extern const char* kImageUrlMalformedErrorMessage;
42+
extern const char* kUnsupportedVariantTypeErrorMessage;
43+
extern const char* kRecordImpressionFailureErrorMessage;
4244

4345
namespace internal {
4446
class AdViewInternal;

gma/src/common/native_ad.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "app/src/assert.h"
2020
#include "app/src/include/firebase/future.h"
21+
#include "app/src/include/firebase/variant.h"
2122
#include "gma/src/common/gma_common.h"
2223
#include "gma/src/common/native_ad_internal.h"
2324

@@ -84,5 +85,35 @@ const std::vector<NativeAdImage>& NativeAd::images() const {
8485
return internal_->images();
8586
}
8687

88+
Future<void> NativeAd::RecordImpression(const Variant& impression_data) {
89+
if (!impression_data.is_map()) {
90+
return CreateAndCompleteFuture(
91+
firebase::gma::internal::kNativeAdFnRecordImpression,
92+
kAdErrorCodeInvalidArgument, kUnsupportedVariantTypeErrorMessage,
93+
&internal_->future_data_);
94+
}
95+
return internal_->RecordImpression(impression_data);
96+
}
97+
98+
Future<void> NativeAd::RecordImpressionLastResult() const {
99+
return internal_->GetLastResult(
100+
firebase::gma::internal::kNativeAdFnRecordImpression);
101+
}
102+
103+
Future<void> NativeAd::PerformClick(const Variant& click_data) {
104+
if (!click_data.is_map()) {
105+
return CreateAndCompleteFuture(
106+
firebase::gma::internal::kNativeAdFnPerformClick,
107+
kAdErrorCodeInvalidArgument, kUnsupportedVariantTypeErrorMessage,
108+
&internal_->future_data_);
109+
}
110+
return internal_->PerformClick(click_data);
111+
}
112+
113+
Future<void> NativeAd::PerformClickLastResult() const {
114+
return internal_->GetLastResult(
115+
firebase::gma::internal::kNativeAdFnPerformClick);
116+
}
117+
87118
} // namespace gma
88119
} // namespace firebase

0 commit comments

Comments
 (0)