Skip to content

Commit

Permalink
Merge branch 'main' into gma-2024-ios
Browse files Browse the repository at this point in the history
  • Loading branch information
jonsimantov authored Feb 20, 2024
2 parents a417079 + 3fd90d5 commit 507bf51
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 2 deletions.
17 changes: 17 additions & 0 deletions gma/integration_test/src/integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2170,6 +2170,10 @@ TEST_F(FirebaseGmaTest, TestNativeRecordImpression) {
WaitForCompletion(native_ad->Initialize(app_framework::GetWindowContext()),
"Initialize");

// Set the listener.
TestAdListener ad_listener;
native_ad->SetAdListener(&ad_listener);

// When the NativeAd is initialized, load an ad.
firebase::Future<firebase::gma::AdResult> load_ad_future =
native_ad->LoadAd(kNativeAdUnit, GetAdRequest());
Expand Down Expand Up @@ -2199,6 +2203,10 @@ TEST_F(FirebaseGmaTest, TestNativeRecordImpression) {
firebase::gma::kAdErrorCodeInvalidRequest);
#endif

// Use an allowlisted Ad unit ID that can record an impression, to verify
// the impression count while testing locally.
EXPECT_EQ(ad_listener.num_on_ad_impression_, 0);

firebase::Variant str_variant =
firebase::Variant::FromMutableString("test");
WaitForCompletion(native_ad->RecordImpression(str_variant),
Expand All @@ -2221,6 +2229,10 @@ TEST_F(FirebaseGmaTest, TestNativePerformClick) {
WaitForCompletion(native_ad->Initialize(app_framework::GetWindowContext()),
"Initialize");

// Set the listener.
TestAdListener ad_listener;
native_ad->SetAdListener(&ad_listener);

// When the NativeAd is initialized, load an ad.
firebase::Future<firebase::gma::AdResult> load_ad_future =
native_ad->LoadAd(kNativeAdUnit, GetAdRequest());
Expand All @@ -2241,6 +2253,11 @@ TEST_F(FirebaseGmaTest, TestNativePerformClick) {
// Android and iOS doesn't have a return type for this API.
WaitForCompletion(native_ad->PerformClick(click_payload), "PerformClick");

// Test Ad unit IDs are not allowlisted to use PerformClick API and the
// request is expected to be rejected by the server. Use an allowlisted Ad
// unit ID to verify the ad click count while testing locally.
EXPECT_EQ(ad_listener.num_on_ad_clicked_, 0);

firebase::Variant str_variant =
firebase::Variant::FromMutableString("test");
WaitForCompletion(native_ad->PerformClick(str_variant), "PerformClick 2",
Expand Down
45 changes: 45 additions & 0 deletions gma/src/android/gma_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,43 @@ void JNI_NativeAd_completeLoadedAd(JNIEnv* env, jclass clazz, jlong data_ptr,
env->DeleteLocalRef(j_response_info);
}

void JNI_NativeAd_notifyAdClicked(JNIEnv* env, jclass clazz, jlong data_ptr) {
FIREBASE_ASSERT(env);
FIREBASE_ASSERT(data_ptr);

firebase::gma::internal::NativeAdInternal* internal =
reinterpret_cast<firebase::gma::internal::NativeAdInternal*>(data_ptr);
internal->NotifyListenerAdClicked();
}

void JNI_NativeAd_notifyAdClosed(JNIEnv* env, jclass clazz, jlong data_ptr) {
FIREBASE_ASSERT(env);
FIREBASE_ASSERT(data_ptr);

firebase::gma::internal::NativeAdInternal* internal =
reinterpret_cast<firebase::gma::internal::NativeAdInternal*>(data_ptr);
internal->NotifyListenerAdClosed();
}

void JNI_NativeAd_notifyAdImpression(JNIEnv* env, jclass clazz,
jlong data_ptr) {
FIREBASE_ASSERT(env);
FIREBASE_ASSERT(data_ptr);

firebase::gma::internal::NativeAdInternal* internal =
reinterpret_cast<firebase::gma::internal::NativeAdInternal*>(data_ptr);
internal->NotifyListenerAdImpression();
}

void JNI_NativeAd_notifyAdOpened(JNIEnv* env, jclass clazz, jlong data_ptr) {
FIREBASE_ASSERT(env);
FIREBASE_ASSERT(data_ptr);

firebase::gma::internal::NativeAdInternal* internal =
reinterpret_cast<firebase::gma::internal::NativeAdInternal*>(data_ptr);
internal->NotifyListenerAdOpened();
}

void JNI_NativeImage_completeLoadedImage(JNIEnv* env, jclass clazz,
jlong data_ptr,
jobject j_image_bytes) {
Expand Down Expand Up @@ -1260,6 +1297,14 @@ bool RegisterNatives() {
reinterpret_cast<void*>(&JNI_completeLoadAdError)},
{"completeNativeLoadAdInternalError", "(JILjava/lang/String;)V",
reinterpret_cast<void*>(&JNI_completeLoadAdInternalError)},
{"notifyAdClicked", "(J)V",
reinterpret_cast<void*>(&JNI_NativeAd_notifyAdClicked)},
{"notifyAdClosed", "(J)V",
reinterpret_cast<void*>(&JNI_NativeAd_notifyAdClosed)},
{"notifyAdImpression", "(J)V",
reinterpret_cast<void*>(&JNI_NativeAd_notifyAdImpression)},
{"notifyAdOpened", "(J)V",
reinterpret_cast<void*>(&JNI_NativeAd_notifyAdOpened)},
};

static const JNINativeMethod kNativeImageMethods[] = {
Expand Down
4 changes: 4 additions & 0 deletions gma/src/common/native_ad.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ Future<AdResult> NativeAd::LoadAdLastResult() const {
return internal_->GetLoadAdLastResult();
}

void NativeAd::SetAdListener(AdListener* listener) {
internal_->SetAdListener(listener);
}

const NativeAdImage& NativeAd::icon() const { return internal_->icon(); }

const std::vector<NativeAdImage>& NativeAd::images() const {
Expand Down
35 changes: 34 additions & 1 deletion gma/src/common/native_ad_internal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ namespace gma {
namespace internal {

NativeAdInternal::NativeAdInternal(NativeAd* base)
: base_(base), future_data_(kNativeAdFnCount) {}
: base_(base), future_data_(kNativeAdFnCount), ad_listener_(nullptr) {}

NativeAdInternal* NativeAdInternal::CreateInstance(NativeAd* base) {
#if FIREBASE_PLATFORM_ANDROID
Expand All @@ -61,6 +61,39 @@ Future<AdResult> NativeAdInternal::GetLoadAdLastResult() {
future_data_.future_impl.LastResult(kNativeAdFnLoadAd));
}

void NativeAdInternal::SetAdListener(AdListener* listener) {
MutexLock lock(listener_mutex_);
ad_listener_ = listener;
}

void NativeAdInternal::NotifyListenerAdClicked() {
MutexLock lock(listener_mutex_);
if (ad_listener_ != nullptr) {
ad_listener_->OnAdClicked();
}
}

void NativeAdInternal::NotifyListenerAdClosed() {
MutexLock lock(listener_mutex_);
if (ad_listener_ != nullptr) {
ad_listener_->OnAdClosed();
}
}

void NativeAdInternal::NotifyListenerAdImpression() {
MutexLock lock(listener_mutex_);
if (ad_listener_ != nullptr) {
ad_listener_->OnAdImpression();
}
}

void NativeAdInternal::NotifyListenerAdOpened() {
MutexLock lock(listener_mutex_);
if (ad_listener_ != nullptr) {
ad_listener_->OnAdOpened();
}
}

void NativeAdInternal::insert_image(const NativeAdImage& image,
const std::string& image_type) {
if (image_type == "icon") {
Expand Down
15 changes: 15 additions & 0 deletions gma/src/common/native_ad_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ class NativeAdInternal {
// Retrieves the most recent AdResult future for the LoadAd function.
Future<AdResult> GetLoadAdLastResult();

// Sets an AdListener for this ad view.
virtual void SetAdListener(AdListener* listener);

// Notifies the Ad listener (if one exists) that an event has occurred.
void NotifyListenerAdClicked();
void NotifyListenerAdClosed();
void NotifyListenerAdImpression();
void NotifyListenerAdOpened();

// Returns true if the NativeAd has been initialized.
virtual bool is_initialized() const = 0;

Expand Down Expand Up @@ -101,6 +110,9 @@ class NativeAdInternal {
// Future data used to synchronize asynchronous calls.
FutureData future_data_;

// Listener for NativeAd Lifecycle event callbacks.
AdListener* ad_listener_;

// Tracks the native ad icon asset.
NativeAdImage icon_;

Expand All @@ -109,6 +121,9 @@ class NativeAdInternal {

// Tracks the native ad choices icon asset.
NativeAdImage adchoices_icon_;

// Lock object for accessing ad_listener_.
Mutex listener_mutex_;
};

} // namespace internal
Expand Down
6 changes: 6 additions & 0 deletions gma/src/include/firebase/gma/internal/native_ad.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ class NativeAd {
/// LoadAd.
Future<AdResult> LoadAdLastResult() const;

/// Sets an AdListener for this native ad.
///
/// @param[in] listener An AdListener object which will be invoked
/// when lifecycle events occur on this NativeAd.
void SetAdListener(AdListener* listener);

/// Returns the associated icon asset of the native ad.
const NativeAdImage& icon() const;

Expand Down
18 changes: 18 additions & 0 deletions gma/src/ios/FADNativeDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,22 @@ - (void)adLoader:(GADAdLoader *)adLoader didReceiveNativeAd:(GADNativeAd *)nativ
_nativeAd->NativeAdDidReceiveAd(nativeAd);
}

#pragma mark GADNativeAdDelegate implementation

- (void)nativeAdDidRecordClick:(nonnull GADNativeAd *)nativeAd {
_nativeAd->NotifyListenerAdClicked();
}

- (void)nativeAdDidRecordImpression:(nonnull GADNativeAd *)nativeAd {
_nativeAd->NotifyListenerAdImpression();
}

- (void)nativeAdWillPresentScreen:(nonnull GADNativeAd *)nativeAd {
_nativeAd->NotifyListenerAdOpened();
}

- (void)nativeAdDidDismissScreen:(nonnull GADNativeAd *)nativeAd {
_nativeAd->NotifyListenerAdClosed();
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public void run() {
});
}

/** Disconnect the helper from the interstital ad. */
/** Disconnect the helper from the native ad. */
public void disconnect() {
synchronized (mNativeLock) {
mNativeAdInternalPtr = CPP_NULLPTR;
Expand Down Expand Up @@ -263,6 +263,42 @@ public void onNativeAdLoaded(NativeAd ad) {
}
}
}

@Override
public void onAdClicked() {
synchronized (mNativeLock) {
if (mNativeAdInternalPtr != CPP_NULLPTR) {
notifyAdClicked(mNativeAdInternalPtr);
}
}
}

@Override
public void onAdImpression() {
synchronized (mNativeLock) {
if (mNativeAdInternalPtr != CPP_NULLPTR) {
notifyAdImpression(mNativeAdInternalPtr);
}
}
}

@Override
public void onAdClosed() {
synchronized (mNativeLock) {
if (mNativeAdInternalPtr != CPP_NULLPTR) {
notifyAdClosed(mNativeAdInternalPtr);
}
}
}

@Override
public void onAdOpened() {
synchronized (mNativeLock) {
if (mNativeAdInternalPtr != CPP_NULLPTR) {
notifyAdOpened(mNativeAdInternalPtr);
}
}
}
}

/** Native callback to instruct the C++ wrapper to complete the corresponding future. */
Expand All @@ -287,4 +323,16 @@ public static native void completeNativeLoadAdError(
*/
public static native void completeNativeLoadAdInternalError(
long nativeInternalPtr, int gmaErrorCode, String errorMessage);

/** Native callback to notify the C++ wrapper of an ad clicked event */
public static native void notifyAdClicked(long nativeInternalPtr);

/** Native callback to notify the C++ wrapper of an ad closed event */
public static native void notifyAdClosed(long nativeInternalPtr);

/** Native callback to notify the C++ wrapper of an ad impression event */
public static native void notifyAdImpression(long nativeInternalPtr);

/** Native callback to notify the C++ wrapper of an ad opened event */
public static native void notifyAdOpened(long nativeInternalPtr);
}

0 comments on commit 507bf51

Please sign in to comment.