Skip to content

Add support for User Messaging Platform SDK on Android #1428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 58 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
3a2358b
Added debug device ID fetch to Android.
jonsimantov Aug 16, 2023
81a88ee
Add Java method for obtaining Android ID from secure settings.
jonsimantov Aug 16, 2023
661af54
Update android ID algorithm.
jonsimantov Aug 16, 2023
baddc6d
Add flatbuffers patch when building for Android.
jonsimantov Aug 16, 2023
4a4a32e
Add stub Android files.
jonsimantov Aug 16, 2023
885c68a
Fix path.
jonsimantov Aug 16, 2023
089ca5d
Add ConsentInfoHelper class with some starting functionality.
jonsimantov Aug 17, 2023
376b4b8
Fix GetDebugDeviceId on Android.
jonsimantov Aug 17, 2023
98ca5ec
Format code.
jonsimantov Aug 17, 2023
f1a9a78
Add UMP dependency.
jonsimantov Aug 17, 2023
6f03e3c
Fix overrides.
jonsimantov Aug 17, 2023
adcca1e
Add initialization.
jonsimantov Aug 17, 2023
54f4054
Lint.
jonsimantov Aug 17, 2023
acf9ba1
Lint.
jonsimantov Aug 17, 2023
cdfc325
Move UMP resources to their own resource file and class path.
jonsimantov Aug 17, 2023
971a00c
Fix relocated UMP resources.
jonsimantov Aug 17, 2023
c7e5169
Add enum conversion and fix build.
jonsimantov Aug 17, 2023
4d0db12
Add enum cache.
jonsimantov Aug 17, 2023
a120870
Android implementation of ConsentInfo functionality.
jonsimantov Aug 18, 2023
a61afb8
Format code.
jonsimantov Aug 18, 2023
bc1aa9c
Fix JNI type.
jonsimantov Aug 18, 2023
5beea2e
Fix Java build errors and format code.
jonsimantov Aug 18, 2023
5262bd4
Fix call.
jonsimantov Aug 18, 2023
413d3d9
Merge branch 'feature_branch/ump-sdk' into feature/ump-sdk-android
jonsimantov Aug 18, 2023
af4b024
Fix initialization.
jonsimantov Aug 18, 2023
a6a37af
Fix for debugDeviceId
jonsimantov Aug 18, 2023
839e84a
Remove extra Enum method, and also format code.
jonsimantov Aug 18, 2023
32b54b3
Fix error message handling for Unavailable error. And format code.
jonsimantov Aug 18, 2023
9cde0b9
Fix compile issue.
jonsimantov Aug 18, 2023
11729d6
Remove extra debugging output.
jonsimantov Aug 18, 2023
6b23636
Remove test filter for UMP only.
jonsimantov Aug 18, 2023
97b2ff2
Remove extraneous HasExceptionOccurred function since ExceptionCheck …
jonsimantov Aug 18, 2023
56b320c
Add OperationInProgress check to iOS SDK as well, and a test for it.
jonsimantov Aug 19, 2023
589f57a
Remove lint abortOnError false
jonsimantov Aug 19, 2023
639c489
Try enabling parallel gradle builds for Windows.
jonsimantov Aug 19, 2023
bfd31c1
Restore script.
jonsimantov Aug 19, 2023
cb32122
Remove lint on error abort.
jonsimantov Aug 19, 2023
aafb299
Remove extra manifest file.
jonsimantov Aug 19, 2023
d6fc10b
Restore build.gradle for GMA library proper
jonsimantov Aug 19, 2023
1f9c98a
Temporarily remove ump_resources to see if this fixes Windows build h…
jonsimantov Aug 19, 2023
02778b4
Remove Flatbuffers patch to diagnose Windows hang.
jonsimantov Aug 19, 2023
c8045bc
Fix build error.
jonsimantov Aug 19, 2023
03decca
Add missing dependencies.
jonsimantov Aug 19, 2023
695f723
Revert "Add missing dependencies."
jonsimantov Aug 19, 2023
f45196f
Add ump-resources back in.
jonsimantov Aug 19, 2023
da195ba
Add code back in.
jonsimantov Aug 19, 2023
8105db1
Modify comment.
jonsimantov Aug 19, 2023
194d089
Remove lint abort.
jonsimantov Aug 19, 2023
3a348d6
Add compatibility version.
jonsimantov Aug 19, 2023
41794c0
Move ConsentInfoHelper class into regular gma_resources.
jonsimantov Aug 19, 2023
c68059a
Remove comment about build hang because spoiler alert, it doesn't cau…
jonsimantov Aug 19, 2023
65af440
Ensure that GMA and UMP only load their shared class files once.
jonsimantov Aug 19, 2023
67d4cf8
Rename mutex.
jonsimantov Aug 19, 2023
eaecc6e
Merge branch 'feature_branch/ump-sdk' into feature/ump-sdk-android
jonsimantov Sep 12, 2023
6225dcf
Update copyright date and fix lock issue.
jonsimantov Sep 12, 2023
b15029b
Move lock to later in the destructor.
jonsimantov Sep 12, 2023
21fa4cd
Format code.
jonsimantov Sep 12, 2023
924981b
Fix non-UI tests.
jonsimantov Sep 13, 2023
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
3 changes: 2 additions & 1 deletion Android/firebase_dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ def firebaseDependenciesMap = [
'dynamic_links' : ['com.google.firebase:firebase-dynamic-links'],
'firestore' : ['com.google.firebase:firebase-firestore'],
'functions' : ['com.google.firebase:firebase-functions'],
'gma' : ['com.google.android.gms:play-services-ads:22.3.0'],
'gma' : ['com.google.android.gms:play-services-ads:22.3.0',
'com.google.android.ump:user-messaging-platform:2.1.0'],
'installations' : ['com.google.firebase:firebase-installations'],
'invites' : ['com.google.firebase:firebase-invites'],
// Messaging has an additional local dependency to include.
Expand Down
2 changes: 1 addition & 1 deletion gma/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ binary_to_array("gma_resources"
# Source files used by the Android implementation.
set(android_SRCS
${gma_resources_source}
src/stub/ump/consent_info_internal_stub.cc
src/android/ump/consent_info_internal_android.cc
src/android/ad_request_converter.cc
src/android/ad_error_android.cc
src/android/adapter_response_info_android.cc
Expand Down
6 changes: 6 additions & 0 deletions gma/gma_resources/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ allprojects {
apply plugin: 'com.android.library'

android {
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}

compileSdkVersion 28

sourceSets {
Expand All @@ -48,6 +53,7 @@ dependencies {
implementation platform('com.google.firebase:firebase-bom:32.2.3')
implementation 'com.google.firebase:firebase-analytics'
implementation 'com.google.android.gms:play-services-ads:22.3.0'
implementation 'com.google.android.ump:user-messaging-platform:2.1.0'
}

afterEvaluate {
Expand Down
3 changes: 3 additions & 0 deletions gma/integration_test/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ android {
proguardFile file('proguard.pro')
}
}
lintOptions {
abortOnError false
}
}

apply from: "$gradle.firebase_cpp_sdk_dir/Android/firebase_dependencies.gradle"
Expand Down
95 changes: 94 additions & 1 deletion gma/integration_test/src/integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ void FirebaseGmaTest::SetUp() {
// debugging. They appear as a long string of hex characters.
firebase::gma::RequestConfiguration request_configuration;
request_configuration.test_device_ids = kTestDeviceIDs;
request_configuration.test_device_ids.push_back(GetDebugDeviceId());
firebase::gma::SetRequestConfiguration(request_configuration);
}

Expand Down Expand Up @@ -332,6 +333,7 @@ void FirebaseGmaUITest::SetUp() {
// debugging. They appear as a long string of hex characters.
firebase::gma::RequestConfiguration request_configuration;
request_configuration.test_device_ids = kTestDeviceIDs;
request_configuration.test_device_ids.push_back(GetDebugDeviceId());
firebase::gma::SetRequestConfiguration(request_configuration);
}

Expand Down Expand Up @@ -2493,7 +2495,12 @@ class FirebaseGmaUmpTest : public FirebaseGmaTest {

void FirebaseGmaUmpTest::InitializeUmp(ResetOption reset) {
using firebase::gma::ump::ConsentInfo;
consent_info_ = ConsentInfo::GetInstance(*shared_app_);
firebase::InitResult result;
consent_info_ = ConsentInfo::GetInstance(*shared_app_, &result);

EXPECT_NE(consent_info_, nullptr);
EXPECT_EQ(result, firebase::kInitResultSuccess);

if (consent_info_ != nullptr && reset == kReset) {
consent_info_->Reset();
}
Expand Down Expand Up @@ -2937,4 +2944,90 @@ TEST_F(FirebaseGmaUmpTest, TestUmpCleanupRaceCondition) {
EXPECT_EQ(future_show.status(), firebase::kFutureStatusInvalid);
}

TEST_F(FirebaseGmaUmpTest, TestUmpMethodsReturnOperationInProgress) {
SKIP_TEST_ON_DESKTOP;

using firebase::gma::ump::ConsentFormStatus;
using firebase::gma::ump::ConsentRequestParameters;
using firebase::gma::ump::ConsentStatus;

// Check that all of the UMP operations properly return an OperationInProgress
// error if called more than once at the same time. Each step of this test is
// inherently flaky, so add flaky test blocks all over.

ConsentRequestParameters params;
params.tag_for_under_age_of_consent = false;
params.debug_settings.debug_geography =
ShouldRunUITests() ? firebase::gma::ump::kConsentDebugGeographyEEA
: firebase::gma::ump::kConsentDebugGeographyNonEEA;
params.debug_settings.debug_device_ids = kTestDeviceIDs;
params.debug_settings.debug_device_ids.push_back(GetDebugDeviceId());

FLAKY_TEST_SECTION_BEGIN();
firebase::Future<void> future_request_1 =
consent_info_->RequestConsentInfoUpdate(params);
firebase::Future<void> future_request_2 =
consent_info_->RequestConsentInfoUpdate(params);
WaitForCompletion(
future_request_2, "RequestConsentInfoUpdate second",
firebase::gma::ump::kConsentRequestErrorOperationInProgress);
WaitForCompletion(future_request_1, "RequestConsentInfoUpdate first");
FLAKY_TEST_SECTION_END();

if (ShouldRunUITests()) {
// The below should only be checked if UI tests are enabled, as they
// require some interaction.
FLAKY_TEST_SECTION_BEGIN();
firebase::Future<void> future_load_1 = consent_info_->LoadConsentForm();
firebase::Future<void> future_load_2 = consent_info_->LoadConsentForm();
WaitForCompletion(future_load_2, "LoadConsentForm second",
firebase::gma::ump::kConsentFormErrorOperationInProgress);
WaitForCompletion(future_load_1, "LoadConsentForm first");
FLAKY_TEST_SECTION_END();

FLAKY_TEST_SECTION_BEGIN();
firebase::Future<void> future_show_1 =
consent_info_->ShowConsentForm(app_framework::GetWindowController());
firebase::Future<void> future_show_2 =
consent_info_->ShowConsentForm(app_framework::GetWindowController());
WaitForCompletion(future_show_2, "ShowConsentForm second",
firebase::gma::ump::kConsentFormErrorOperationInProgress);
WaitForCompletion(future_show_1, "ShowConsentForm first");
FLAKY_TEST_SECTION_END();

FLAKY_TEST_SECTION_BEGIN();
firebase::Future<void> future_privacy_1 =
consent_info_->ShowPrivacyOptionsForm(
app_framework::GetWindowController());
firebase::Future<void> future_privacy_2 =
consent_info_->ShowPrivacyOptionsForm(
app_framework::GetWindowController());
WaitForCompletion(future_privacy_2, "ShowPrivacyOptionsForm second",
firebase::gma::ump::kConsentFormErrorOperationInProgress);
WaitForCompletion(future_privacy_1, "ShowPrivacyOptionsForm first");
FLAKY_TEST_SECTION_END();

consent_info_->Reset();
// Request again so we can test LoadAndShowConsentFormIfRequired.
WaitForCompletion(consent_info_->RequestConsentInfoUpdate(params),
"RequestConsentInfoUpdate");

FLAKY_TEST_SECTION_BEGIN();
firebase::Future<void> future_load_and_show_1 =
consent_info_->LoadAndShowConsentFormIfRequired(
app_framework::GetWindowController());
firebase::Future<void> future_load_and_show_2 =
consent_info_->LoadAndShowConsentFormIfRequired(
app_framework::GetWindowController());
WaitForCompletion(future_load_and_show_2,
"LoadAndShowConsentFormIfRequired second",
firebase::gma::ump::kConsentFormErrorOperationInProgress);
WaitForCompletion(future_load_and_show_1,
"LoadAndShowConsentFormIfRequired first");
FLAKY_TEST_SECTION_END();
} else {
LogInfo("Skipping methods that require user interaction.");
}
}

} // namespace firebase_testapp_automated
28 changes: 22 additions & 6 deletions gma/src/android/gma_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@
namespace firebase {
namespace gma {

namespace internal {
::firebase::Mutex g_cached_gma_embedded_files_mutex;
std::vector<::firebase::internal::EmbeddedFile>* g_cached_gma_embedded_files =
nullptr;
} // namespace internal

METHOD_LOOKUP_DEFINITION(mobile_ads,
PROGUARD_KEEP_CLASS
"com/google/android/gms/ads/MobileAds",
Expand Down Expand Up @@ -308,12 +314,22 @@ Future<AdapterInitializationStatus> Initialize(JNIEnv* env, jobject activity,
return Future<AdapterInitializationStatus>();
}

const std::vector<firebase::internal::EmbeddedFile> embedded_files =
util::CacheEmbeddedFiles(env, activity,
firebase::internal::EmbeddedFile::ToVector(
firebase_gma::gma_resources_filename,
firebase_gma::gma_resources_data,
firebase_gma::gma_resources_size));
// Between this and UMP, we only want to load these files once.
{
MutexLock lock(internal::g_cached_gma_embedded_files_mutex);
if (internal::g_cached_gma_embedded_files == nullptr) {
internal::g_cached_gma_embedded_files =
new std::vector<firebase::internal::EmbeddedFile>();
*internal::g_cached_gma_embedded_files =
util::CacheEmbeddedFiles(env, activity,
firebase::internal::EmbeddedFile::ToVector(
firebase_gma::gma_resources_filename,
firebase_gma::gma_resources_data,
firebase_gma::gma_resources_size));
}
}
const std::vector<firebase::internal::EmbeddedFile>& embedded_files =
*internal::g_cached_gma_embedded_files;

if (!(mobile_ads::CacheMethodIds(env, activity) &&
ad_request_builder::CacheMethodIds(env, activity) &&
Expand Down
12 changes: 12 additions & 0 deletions gma/src/android/gma_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@

#include <jni.h>

#include <vector>

#include "app/src/embedded_file.h"
#include "app/src/util_android.h"
#include "firebase/internal/mutex.h"
#include "gma/src/common/gma_common.h"

namespace firebase {
Expand Down Expand Up @@ -189,6 +193,14 @@ void ReleaseClasses(JNIEnv* env);
jobject CreateJavaAdSize(JNIEnv* env, jobject activity,
const AdSize& an_ad_size);

namespace internal {
// GMA and UMP share embedded dex files; this ensures
// that they are only loaded once each run.
extern ::firebase::Mutex g_cached_gma_embedded_files_mutex;
extern std::vector<::firebase::internal::EmbeddedFile>*
g_cached_gma_embedded_files;
} // namespace internal

} // namespace gma
} // namespace firebase

Expand Down
Loading