Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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: 3 additions & 0 deletions DemoApp/DemoAppJava/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ dependencies {
// Google Mobile Ads
implementation 'com.google.android.gms:play-services-ads:24.6.0'

// Prebid Ads
implementation "org.prebid:prebid-mobile-sdk:3.0.2"

// Base Android
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.0.21"
implementation 'com.android.support:multidex:1.0.3'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package co.optable.demoappjava;

import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import co.optable.android_sdk.OptableSDK;
import com.google.android.gms.ads.MobileAds;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import org.prebid.mobile.PrebidMobile;
import org.prebid.mobile.api.data.InitializationStatus;

public class MainActivity extends AppCompatActivity {

private static final String TAG = "MainActivity";

public static OptableSDK OPTABLE;

@Override
Expand All @@ -20,13 +26,35 @@ protected void onCreate(Bundle savedInstanceState) {

MainActivity.OPTABLE = new OptableSDK(this.getApplicationContext(), "sandbox.optable.co", "ios-sdk-demo");

initGoogleAds();
initPrebidSdk();
initUi();
}

private void initGoogleAds() {
MobileAds.initialize(this, initializationStatus -> {
});
}

private void initPrebidSdk() {
PrebidMobile.setPrebidServerAccountId("0689a263-318d-448b-a3d4-b02e8a709d9d");
PrebidMobile.initializeSdk(getApplicationContext(), "https://prebid-server-test-j.prebid.org/openrtb2/auction", status -> {
if (status == InitializationStatus.SUCCEEDED) {
Log.d(TAG, "SDK initialized successfully!");
} else {
Log.e(TAG, "SDK initialization error: " + status.getDescription());
}
});
}

private void initUi() {
BottomNavigationView navView = findViewById(R.id.nav_view);
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(R.id.navigation_identify, R.id.navigation_gambanner).build();
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_identify,
R.id.navigation_gambanner,
R.id.navigation_prebid
).build();
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,

private void initUi(View root) {
mAdView = root.findViewById(R.id.publisherAdView);
statusTextView = root.findViewById(R.id.targetingDataView);
statusTextView = root.findViewById(R.id.statusTextView);

root.findViewById(R.id.btnLoadBanner).setOnClickListener(view -> onClickLoadAd());
root.findViewById(R.id.btnCachedBanner).setOnClickListener(view -> onClickCachedBanner());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
package co.optable.demoappjava.ui;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import co.optable.android_sdk.OptableSDK;
import co.optable.demoappjava.MainActivity;
import co.optable.demoappjava.R;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.LoadAdError;
import com.google.android.gms.ads.admanager.AdManagerAdRequest;
import com.google.android.gms.ads.admanager.AdManagerAdView;
import org.jetbrains.annotations.NotNull;
import org.prebid.mobile.BannerAdUnit;
import org.prebid.mobile.ExternalUserId;
import org.prebid.mobile.TargetingParams;

import java.util.*;

public class PrebidBannerFragment extends Fragment {

private static final String GAM_AD_UNIT_ID = "/21808260008/prebid_demo_app_original_api_banner";
private static final String PREBID_CONFIG_ID = "prebid-demo-banner-320-50";
private static final int WIDTH = 320;
private static final int HEIGHT = 50;

private AdManagerAdView adView;
private BannerAdUnit prebidAdUnit;

private ViewGroup adContainer;
private TextView statusTextView;

@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_prebid, container, false);
initUi(root);
return root;
}

private void initUi(View root) {
statusTextView = root.findViewById(R.id.statusTextView);
adContainer = root.findViewById(R.id.adContainer);

root.findViewById(R.id.btnLoadBanner).setOnClickListener(view -> onClickLoadAd());
root.findViewById(R.id.btnCachedBanner).setOnClickListener(view -> onClickCachedBanner());
root.findViewById(R.id.btnClearCache).setOnClickListener(view -> onClickClearCache());
}

/**
* Loads targeting data and then the GAM banner
*/
private void onClickLoadAd() {
statusTextView.setText("");

MainActivity.OPTABLE
.targeting()
.observe(getViewLifecycleOwner(), result -> {
AdManagerAdRequest.Builder adRequestBuilder = new AdManagerAdRequest.Builder();

if (result.getStatus() == OptableSDK.Status.SUCCESS) {
HashMap<String, List<String>> data = result.getData();
changeStatusText("Loaded Optable targeting data", data);

if (data != null) {
for (String key : data.keySet()) {
List<String> values = data.get(key);
if (values == null) continue;
adRequestBuilder.addCustomTargeting(key, values);
}
}
} else {
changeStatusText("Error loading Optable targeting data: " + result.getMessage(), null);
}

loadPrebidAd(adRequestBuilder, result.getData());
profile();
witness();
});
}

private void loadPrebidAd(AdManagerAdRequest.Builder adRequestBuilder, @Nullable HashMap<String, List<String>> optableTargeting) {
prebidAdUnit = new BannerAdUnit(PREBID_CONFIG_ID, WIDTH, HEIGHT);
applyOptableToPrebid(optableTargeting);
prebidAdUnit.fetchDemand(adRequestBuilder, resultCode -> {
appendStatusText("Prebid ads loading status: " + resultCode.toString());
loadGamAd(adRequestBuilder);
});
}

private void applyOptableToPrebid(HashMap<String, List<String>> optableTargeting) {
if (optableTargeting != null) {
List<ExternalUserId.UniqueId> uniqueIds = new ArrayList<>();
for (Map.Entry<String, List<String>> entry : optableTargeting.entrySet()) {
List<String> value = entry.getValue();
if (value == null) continue;
for (String id : value) {
uniqueIds.add(new ExternalUserId.UniqueId(id, 1));
}
}
List<ExternalUserId> externalUserIds = new ArrayList<>();
externalUserIds.add(new ExternalUserId("optable.com", uniqueIds));
TargetingParams.setExternalUserIds(externalUserIds);
}
}

private void loadGamAd(AdManagerAdRequest.Builder adRequestBuilder) {
adContainer.removeAllViews();

AdManagerAdRequest adRequest = adRequestBuilder.build();

adView = new AdManagerAdView(requireContext());
adView.setAdUnitId(GAM_AD_UNIT_ID);
adView.setAdSizes(new com.google.android.gms.ads.AdSize(WIDTH, HEIGHT));
adView.setAdListener(new AdListener() {
@Override
public void onAdLoaded() {
super.onAdLoaded();
appendStatusText("Google ad loaded");
}

@Override
public void onAdFailedToLoad(@NonNull @NotNull LoadAdError loadAdError) {
appendStatusText("Google ad failed to load: " + loadAdError.getMessage());
}
});
adView.loadAd(adRequest);

adContainer.addView(adView);
}

/**
* Loads targeting data from cache and then the GAM banner
*/
private void onClickCachedBanner() {
statusTextView.setText("");

AdManagerAdRequest.Builder adRequestBuilder = new AdManagerAdRequest.Builder();
HashMap<String, List<String>> data = MainActivity.OPTABLE.targetingFromCache();

if (data != null) {
changeStatusText("Loaded Optable cached targeting data", data);
for (String key : data.keySet()) {
List<String> values = data.get(key);
if (values == null) continue;
adRequestBuilder.addCustomTargeting(key, values);
}
} else {
changeStatusText("Targeting data cache empty.", null);
}

loadPrebidAd(adRequestBuilder, data);
profile();
witness();
}

/**
* Clears targeting data cache.
*/
private void onClickClearCache() {
statusTextView.setText("Clearing targeting data cache.\n\n");
MainActivity.OPTABLE.targetingClearCache();
}

private void profile() {
HashMap<String, Object> traits = new HashMap<>();
traits.put("gender", "F");
traits.put("age", 38);
traits.put("hasAccount", true);

MainActivity.OPTABLE
.profile(traits)
.observe(getViewLifecycleOwner(), result -> {
if (result.getStatus() == OptableSDK.Status.SUCCESS) {
appendStatusText("Success calling profile API to set traits on user.");
} else {
appendStatusText("Error during sending profile: " + result.getMessage());
}
});
}

private void witness() {
HashMap<String, Object> eventProperties = new HashMap<>();
eventProperties.put("exampleKey", "exampleValue");
eventProperties.put("exampleKey2", 123);
eventProperties.put("exampleKey3", false);

MainActivity.OPTABLE
.witness("GAMBannerFragment.loadAdButtonClicked", eventProperties)
.observe(getViewLifecycleOwner(), result -> {
if (result.getStatus() == OptableSDK.Status.SUCCESS) {
appendStatusText("Success calling witness API to log loadAdButtonClicked event.");
} else {
appendStatusText("Error during sending witness: " + result.getMessage());
}
});
}

private void changeStatusText(@NonNull String message, @Nullable HashMap<String, List<String>> optableResponse) {
StringBuilder formattedMessage = new StringBuilder(message);
if (optableResponse != null) {
formattedMessage.append("\n\nTargeting data: ");
for (Map.Entry<String, ? extends Collection<?>> entry : optableResponse.entrySet()) {
formattedMessage.append(entry.getKey())
.append(" = ")
.append(entry.getValue())
.append("\n");
}
}
statusTextView.setText(formattedMessage.toString());
}

private void appendStatusText(@NonNull String message) {
statusTextView.append("\n\n" + message);
}

}
34 changes: 13 additions & 21 deletions DemoApp/DemoAppJava/app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
@@ -1,33 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="?attr/actionBarSize">

<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_nav_menu" />
android:orientation="vertical"
android:layout_height="match_parent">

<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="@id/nav_view"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/mobile_navigation" />

</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/windowBackground"
app:menu="@menu/bottom_nav_menu" />

</LinearLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/targetingDataView"
android:id="@+id/statusTextView"
android:layout_width="291dp"
android:layout_height="346dp"
android:layout_marginTop="100dp"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="50dp"
tools:context=".ui.Identify.IdentifyFragment">

<EditText
Expand Down
Loading