From 22394c28211f748f1ce40ab5f100ca28c9aae198 Mon Sep 17 00:00:00 2001 From: pickerweng Date: Wed, 18 Dec 2024 21:58:23 +0800 Subject: [PATCH] feat: video player sample with Inline AD for CHT --- gradle/libs.versions.toml | 4 + sdkdemo/build.gradle.kts | 5 +- .../io/tenmax/sdkdemo/SupportedSpaces.java | 4 + .../tenmax/sdkdemo/ui/home/HomeFragment.java | 12 ++ .../sdkdemo/ui/video/VideoFragment.java | 146 ++++++++++++++++++ .../sdkdemo/ui/video/VideoViewModel.java | 22 +++ sdkdemo/src/main/res/drawable/ic_close.xml | 5 + sdkdemo/src/main/res/drawable/ic_pause.xml | 5 + sdkdemo/src/main/res/drawable/ic_play.xml | 5 + sdkdemo/src/main/res/layout/fragment_home.xml | 12 ++ .../src/main/res/layout/fragment_video.xml | 46 ++++++ 11 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 sdkdemo/src/main/java/io/tenmax/sdkdemo/ui/video/VideoFragment.java create mode 100644 sdkdemo/src/main/java/io/tenmax/sdkdemo/ui/video/VideoViewModel.java create mode 100644 sdkdemo/src/main/res/drawable/ic_close.xml create mode 100644 sdkdemo/src/main/res/drawable/ic_pause.xml create mode 100644 sdkdemo/src/main/res/drawable/ic_play.xml create mode 100644 sdkdemo/src/main/res/layout/fragment_video.xml diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 949abea..8dbfc7a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,6 +14,8 @@ playServicesAdsIdentifier = "18.1.0" gson = "2.11.0" retrofit = "2.11.0" converterGson = "2.11.0" +media3Exoplayer = "1.5.0" +media3Ui = "1.5.0" [libraries] junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -30,6 +32,8 @@ play-services-ads-identifier = { group = "com.google.android.gms", name = "play- gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" } converter-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "converterGson" } +media3-exoplayer = { group = "androidx.media3", name = "media3-exoplayer", version.ref = "media3Exoplayer" } +media3-ui = { group = "androidx.media3", name = "media3-ui", version.ref = "media3Ui" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } diff --git a/sdkdemo/build.gradle.kts b/sdkdemo/build.gradle.kts index 3f68eda..c825805 100644 --- a/sdkdemo/build.gradle.kts +++ b/sdkdemo/build.gradle.kts @@ -4,7 +4,7 @@ plugins { android { namespace = "io.tenmax.sdkdemo" - compileSdk = 34 + compileSdk = 35 defaultConfig { applicationId = "com.tenmax.sdkdemo" @@ -52,6 +52,7 @@ android { resValue("string", "topBannerId", "aa7947ea8e104da3") resValue("string", "bottomBannerId", "2b07703707354bd6") resValue("string", "floatingId", "5417d8bf58b34bac") + resValue("string", "videoInlineId", "cdc8203a5167467d") resValue("string", "app_name", "TenMaxMobileSDKDemo (CHT)") } create("internal") { @@ -94,6 +95,8 @@ dependencies { implementation(libs.retrofit) implementation(libs.converter.gson) implementation(libs.play.services.ads.identifier) + implementation(libs.media3.exoplayer) + implementation(libs.media3.ui) testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.espresso.core) diff --git a/sdkdemo/src/main/java/io/tenmax/sdkdemo/SupportedSpaces.java b/sdkdemo/src/main/java/io/tenmax/sdkdemo/SupportedSpaces.java index 5268fe4..b2fa10c 100644 --- a/sdkdemo/src/main/java/io/tenmax/sdkdemo/SupportedSpaces.java +++ b/sdkdemo/src/main/java/io/tenmax/sdkdemo/SupportedSpaces.java @@ -23,4 +23,8 @@ static String inlineId(Context context) { static String floatingId(Context context) { return context.getResources().getString(R.string.floatingId); } + + static String videoInlineId(Context context) { + return context.getResources().getString(R.string.videoInlineId); + } } diff --git a/sdkdemo/src/main/java/io/tenmax/sdkdemo/ui/home/HomeFragment.java b/sdkdemo/src/main/java/io/tenmax/sdkdemo/ui/home/HomeFragment.java index efe891c..37b3607 100644 --- a/sdkdemo/src/main/java/io/tenmax/sdkdemo/ui/home/HomeFragment.java +++ b/sdkdemo/src/main/java/io/tenmax/sdkdemo/ui/home/HomeFragment.java @@ -5,6 +5,7 @@ import static io.tenmax.sdkdemo.SupportedSpaces.inlineId; import static io.tenmax.sdkdemo.SupportedSpaces.interstitialId; import static io.tenmax.sdkdemo.SupportedSpaces.topBannerId; +import static io.tenmax.sdkdemo.SupportedSpaces.videoInlineId; import android.os.Bundle; import android.view.LayoutInflater; @@ -20,6 +21,7 @@ import io.tenmax.sdkdemo.R; import io.tenmax.sdkdemo.databinding.FragmentHomeBinding; import io.tenmax.sdkdemo.ui.dashboard.DashboardFragment; +import io.tenmax.sdkdemo.ui.video.VideoFragment; public class HomeFragment extends Fragment { @@ -36,6 +38,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, this.binding.showTopBannerAd.setOnClickListener((view) -> showAd("topBanner", topBannerId(getContext()))); this.binding.showBottomBannerAd.setOnClickListener((view) -> showAd("bottomBanner", bottomBannerId(getContext()))); this.binding.showFloatingAd.setOnClickListener((view) -> showAd("floating", floatingId(getContext()))); + this.binding.videoPausePictureAd.setOnClickListener((view) -> showVideoFragment(videoInlineId(getContext()))); return root; } @@ -60,6 +63,15 @@ private void showAd(String type, String spaceId) { this.pushFragment(dashboard); } + private void showVideoFragment(String spaceId) { + Fragment videoFragment = new VideoFragment(); + Bundle bundle = new Bundle(); + bundle.putString("spaceType", "inline"); + bundle.putString("spaceId", spaceId); + videoFragment.setArguments(bundle); + this.pushFragment(videoFragment); + } + private void pushFragment(Fragment fragment) { FragmentManager manager = getParentFragmentManager(); manager.beginTransaction() diff --git a/sdkdemo/src/main/java/io/tenmax/sdkdemo/ui/video/VideoFragment.java b/sdkdemo/src/main/java/io/tenmax/sdkdemo/ui/video/VideoFragment.java new file mode 100644 index 0000000..13d4e80 --- /dev/null +++ b/sdkdemo/src/main/java/io/tenmax/sdkdemo/ui/video/VideoFragment.java @@ -0,0 +1,146 @@ +package io.tenmax.sdkdemo.ui.video; + +import static io.tenmax.mobilesdk.TenMaxBannerPosition.bottom; +import static io.tenmax.mobilesdk.TenMaxBannerPosition.top; +import static io.tenmax.mobilesdk.TenMaxMobileSDK.bannerAd; +import static io.tenmax.mobilesdk.TenMaxMobileSDK.cleanAd; +import static io.tenmax.mobilesdk.TenMaxMobileSDK.floatingAd; +import static io.tenmax.mobilesdk.TenMaxMobileSDK.inlineAd; +import static io.tenmax.mobilesdk.TenMaxMobileSDK.interstitialAd; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.media3.common.MediaItem; +import androidx.media3.common.Player; +import androidx.media3.exoplayer.ExoPlayer; +import androidx.media3.exoplayer.SimpleExoPlayer; + +import java.util.Map; + +import io.tenmax.mobilesdk.TenMaxAd; +import io.tenmax.mobilesdk.TenMaxAdSessionListener; +import io.tenmax.mobilesdk.TenMaxAdSpace; +import io.tenmax.mobilesdk.TenMaxInitiationCallback; +import io.tenmax.sdkdemo.databinding.FragmentVideoBinding; +import io.tenmax.sdkdemo.ui.SimpleAdSessionListener; +import io.tenmax.sdkdemo.ui.SimpleInitiationCallback; + +public class VideoFragment extends Fragment { + + interface AdInitializer { + TenMaxAd init(String spaceId, Fragment fragment, FragmentVideoBinding binding, TenMaxAdSessionListener listener, TenMaxInitiationCallback callback); + } + + private TenMaxAd presentingAd; + private FragmentVideoBinding binding; + private Player player; + private final Map adInitializers = Map.of( + "inline", (spaceId, fragment, binding, listener, callback) -> inlineAd(spaceId, fragment.getActivity(), binding.inlineAd, options -> { + options.listenSession(listener).monitorInitiation(callback); + }) + ); + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + binding = FragmentVideoBinding.inflate(inflater, container, false); + View root = binding.getRoot(); + binding.adContainer.setVisibility(View.GONE); + binding.closeAd.setVisibility(View.GONE); + binding.adContainer.setOnTouchListener((v, event) -> true); + player = new ExoPlayer.Builder(requireContext()).build(); + binding.playerView.setPlayer(player); + + MediaItem mediaItem = MediaItem.fromUri("https://media.w3.org/2010/05/sintel/trailer.mp4"); + player.setMediaItem(mediaItem); + player.prepare(); + + SimpleAdSessionListener listener = new SimpleAdSessionListener(this.getContext()); + SimpleInitiationCallback callback = new SimpleInitiationCallback(this.getContext()); + if (getArguments() != null) { + String spaceId = getArguments().getString("spaceId"); + String type = getArguments().getString("spaceType"); + AdInitializer initializer = adInitializers.get(type); + if (initializer != null) { + this.presentingAd = initializer.init(spaceId, this, this.binding, listener, callback); + } + } + + player.addListener(new Player.Listener() { + @Override + public void onPlaybackStateChanged(int playbackState) { + if (playbackState == Player.STATE_ENDED) { + showAd(); + } + } + + @Override + public void onIsPlayingChanged(boolean isPlaying) { + if (!isPlaying) { + showAd(); + } else { + hideAd(); + } + } + }); + + binding.playerView.setOnClickListener(view -> { + if (player.isPlaying()) { + player.pause(); + } else { + player.play(); + } + }); + + binding.closeAd.setOnClickListener(view -> { + hideAd(); + player.play(); + }); + + return root; + } + + private void showAd() { + binding.adContainer.setVisibility(View.VISIBLE); + binding.closeAd.setVisibility(View.VISIBLE); + if (presentingAd != null) { + presentingAd.show(); + } + } + + private void hideAd() { + binding.adContainer.setVisibility(View.GONE); + binding.closeAd.setVisibility(View.GONE); + } + + @Override + public void onResume() { + super.onResume(); + if (player != null) { + player.play(); + } + } + + @Override + public void onPause() { + super.onPause(); + if (player != null) { + player.pause(); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + if (player != null) { + player.release(); + player = null; + } + binding = null; + cleanAd(this.presentingAd); + } +} \ No newline at end of file diff --git a/sdkdemo/src/main/java/io/tenmax/sdkdemo/ui/video/VideoViewModel.java b/sdkdemo/src/main/java/io/tenmax/sdkdemo/ui/video/VideoViewModel.java new file mode 100644 index 0000000..f1daa7d --- /dev/null +++ b/sdkdemo/src/main/java/io/tenmax/sdkdemo/ui/video/VideoViewModel.java @@ -0,0 +1,22 @@ +package io.tenmax.sdkdemo.ui.video; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +public class VideoViewModel extends ViewModel { + + private final MutableLiveData mText; + + public VideoViewModel() { + mText = new MutableLiveData<>(); + mText.setValue("This is video fragment"); + } + + public LiveData getText() { + return mText; + } +} + + + diff --git a/sdkdemo/src/main/res/drawable/ic_close.xml b/sdkdemo/src/main/res/drawable/ic_close.xml new file mode 100644 index 0000000..13608b6 --- /dev/null +++ b/sdkdemo/src/main/res/drawable/ic_close.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/sdkdemo/src/main/res/drawable/ic_pause.xml b/sdkdemo/src/main/res/drawable/ic_pause.xml new file mode 100644 index 0000000..7d034e1 --- /dev/null +++ b/sdkdemo/src/main/res/drawable/ic_pause.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/sdkdemo/src/main/res/drawable/ic_play.xml b/sdkdemo/src/main/res/drawable/ic_play.xml new file mode 100644 index 0000000..5321b33 --- /dev/null +++ b/sdkdemo/src/main/res/drawable/ic_play.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/sdkdemo/src/main/res/layout/fragment_home.xml b/sdkdemo/src/main/res/layout/fragment_home.xml index 34a9346..d74ce22 100644 --- a/sdkdemo/src/main/res/layout/fragment_home.xml +++ b/sdkdemo/src/main/res/layout/fragment_home.xml @@ -56,4 +56,16 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/showBottomBannerAd"/> + +