From 0ad9eebf63bc214370db18923a37ffe5bdc75490 Mon Sep 17 00:00:00 2001 From: Bret McGowen Date: Tue, 30 Dec 2014 17:08:31 -0500 Subject: [PATCH] Adds AdvancedExample to demonstrate content playlists and multiple ad tags --- .gitignore | 25 +- AdvancedExample/app/build.gradle | 26 ++ AdvancedExample/app/libs/README | 5 + AdvancedExample/app/proguard-rules.pro | 33 ++ .../app/src/main/AndroidManifest.xml | 28 ++ .../samplevideoplayer/SampleVideoPlayer.java | 161 +++++++++ .../samplevideoplayer/VideoPlayer.java | 95 ++++++ .../v3/samples/videoplayerapp/MyActivity.java | 252 ++++++++++++++ .../v3/samples/videoplayerapp/VideoItem.java | 50 +++ .../videoplayerapp/VideoItemAdapter.java | 59 ++++ .../videoplayerapp/VideoListFragment.java | 122 +++++++ .../videoplayerapp/VideoPlayerController.java | 307 ++++++++++++++++++ .../VideoPlayerWithAdPlayback.java | 265 +++++++++++++++ .../ic_action_play_over_video.png | Bin 0 -> 716 bytes .../main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 9397 bytes .../ic_action_play_over_video.png | Bin 0 -> 494 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 5237 bytes .../ic_action_play_over_video.png | Bin 0 -> 1499 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 14383 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 19388 bytes .../app/src/main/res/drawable/thumbnail1.jpg | Bin 0 -> 23299 bytes .../app/src/main/res/layout/activity_my.xml | 16 + .../src/main/res/layout/fragment_video.xml | 85 +++++ .../main/res/layout/fragment_video_list.xml | 29 ++ .../app/src/main/res/layout/video_item.xml | 27 ++ AdvancedExample/app/src/main/res/menu/my.xml | 9 + .../app/src/main/res/values-w820dp/dimens.xml | 6 + .../app/src/main/res/values/arrays.xml | 46 +++ .../app/src/main/res/values/dimens.xml | 6 + .../app/src/main/res/values/strings.xml | 13 + .../app/src/main/res/values/styles.xml | 21 ++ AdvancedExample/build.gradle | 16 + .../gradle/wrapper/gradle-wrapper.properties | 5 + AdvancedExample/gradlew | 164 ++++++++++ AdvancedExample/gradlew.bat | 90 +++++ AdvancedExample/settings.gradle | 1 + BasicExample/app/libs/README | 0 .../v3/samples/videoplayerapp/MyActivity.java | 2 + .../VideoPlayerWithAdPlayback.java | 4 +- BasicExample/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- BasicExample/gradlew | 0 LICENSE | 0 README.md | 5 +- SampleVideoPlayer/app/libs/README | 0 SampleVideoPlayer/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- SampleVideoPlayer/gradlew | 0 48 files changed, 1959 insertions(+), 22 deletions(-) create mode 100644 AdvancedExample/app/build.gradle create mode 100644 AdvancedExample/app/libs/README create mode 100644 AdvancedExample/app/proguard-rules.pro create mode 100644 AdvancedExample/app/src/main/AndroidManifest.xml create mode 100644 AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/samplevideoplayer/SampleVideoPlayer.java create mode 100644 AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/samplevideoplayer/VideoPlayer.java create mode 100644 AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/MyActivity.java create mode 100644 AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoItem.java create mode 100644 AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoItemAdapter.java create mode 100644 AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoListFragment.java create mode 100644 AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoPlayerController.java create mode 100644 AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoPlayerWithAdPlayback.java create mode 100644 AdvancedExample/app/src/main/res/drawable-hdpi/ic_action_play_over_video.png create mode 100644 AdvancedExample/app/src/main/res/drawable-hdpi/ic_launcher.png create mode 100644 AdvancedExample/app/src/main/res/drawable-mdpi/ic_action_play_over_video.png create mode 100644 AdvancedExample/app/src/main/res/drawable-mdpi/ic_launcher.png create mode 100644 AdvancedExample/app/src/main/res/drawable-xhdpi/ic_action_play_over_video.png create mode 100644 AdvancedExample/app/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100644 AdvancedExample/app/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 AdvancedExample/app/src/main/res/drawable/thumbnail1.jpg create mode 100644 AdvancedExample/app/src/main/res/layout/activity_my.xml create mode 100644 AdvancedExample/app/src/main/res/layout/fragment_video.xml create mode 100644 AdvancedExample/app/src/main/res/layout/fragment_video_list.xml create mode 100644 AdvancedExample/app/src/main/res/layout/video_item.xml create mode 100644 AdvancedExample/app/src/main/res/menu/my.xml create mode 100644 AdvancedExample/app/src/main/res/values-w820dp/dimens.xml create mode 100644 AdvancedExample/app/src/main/res/values/arrays.xml create mode 100644 AdvancedExample/app/src/main/res/values/dimens.xml create mode 100644 AdvancedExample/app/src/main/res/values/strings.xml create mode 100644 AdvancedExample/app/src/main/res/values/styles.xml create mode 100644 AdvancedExample/build.gradle create mode 100644 AdvancedExample/gradle/wrapper/gradle-wrapper.properties create mode 100644 AdvancedExample/gradlew create mode 100644 AdvancedExample/gradlew.bat create mode 100644 AdvancedExample/settings.gradle mode change 100755 => 100644 BasicExample/app/libs/README mode change 100755 => 100644 BasicExample/gradlew mode change 100755 => 100644 LICENSE mode change 100755 => 100644 SampleVideoPlayer/app/libs/README mode change 100755 => 100644 SampleVideoPlayer/gradlew diff --git a/.gitignore b/.gitignore index bf7f06cf..c267cec5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,11 @@ -eclipse/assets -eclipse/bin -eclipse/gen -eclipse/libs/* -!eclipse/libs/README -eclipse/.settings -studio/app/build -studio/app/libs/* -!studio/app/libs/README -studio/gradle -studio/.gradle -studio/.idea -studio/local.properties -eclipse/res/values/version.xml +# Built application files +*.apk +*.ap_ +*.jar + +# Android Studio +.idea +local.properties +*.iml +.gradle +build/ diff --git a/AdvancedExample/app/build.gradle b/AdvancedExample/app/build.gradle new file mode 100644 index 00000000..a7d54fd7 --- /dev/null +++ b/AdvancedExample/app/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.2" + + defaultConfig { + applicationId "com.google.ads.interactivemedia.v3.samples.videoplayerapp" + minSdkVersion 9 + targetSdkVersion 21 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:21.+' + compile 'com.google.android.gms:play-services:6.5+' +} diff --git a/AdvancedExample/app/libs/README b/AdvancedExample/app/libs/README new file mode 100644 index 00000000..8f001fe6 --- /dev/null +++ b/AdvancedExample/app/libs/README @@ -0,0 +1,5 @@ +To integrate the IMA SDK, first download the SDK jar from +https://developers.google.com/interactive-media-ads/downloads +and place it in this folder. +Right click the file in Android Studio, select "Add As Library..." +Select the "app" module, and click OK. diff --git a/AdvancedExample/app/proguard-rules.pro b/AdvancedExample/app/proguard-rules.pro new file mode 100644 index 00000000..30aa3c71 --- /dev/null +++ b/AdvancedExample/app/proguard-rules.pro @@ -0,0 +1,33 @@ +# Add project specific ProGuard rules here. +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# The following rules are used to strip any non essential Google Play Services classes and method. +-keep class * extends java.util.ListResourceBundle { + protected Object[][] getContents(); +} + +-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable { + public static final *** NULL; +} + +-keepnames @com.google.android.gms.common.annotation.KeepName class * +-keepclassmembernames class * { + @com.google.android.gms.common.annotation.KeepName *; +} + +-keepnames class * implements android.os.Parcelable { + public static final ** CREATOR; +} \ No newline at end of file diff --git a/AdvancedExample/app/src/main/AndroidManifest.xml b/AdvancedExample/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..6eff4556 --- /dev/null +++ b/AdvancedExample/app/src/main/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + diff --git a/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/samplevideoplayer/SampleVideoPlayer.java b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/samplevideoplayer/SampleVideoPlayer.java new file mode 100644 index 00000000..68857e6d --- /dev/null +++ b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/samplevideoplayer/SampleVideoPlayer.java @@ -0,0 +1,161 @@ +// Copyright 2014 Google Inc. All Rights Reserved. + +package com.google.ads.interactivemedia.v3.samples.samplevideoplayer; + +import android.content.Context; +import android.media.MediaPlayer; +import android.media.MediaPlayer.OnCompletionListener; +import android.media.MediaPlayer.OnErrorListener; +import android.util.AttributeSet; +import android.widget.MediaController; +import android.widget.VideoView; + +import java.util.ArrayList; +import java.util.List; + +/** + * A VideoView that intercepts various methods and reports them back via a PlayerCallback. + */ +public class SampleVideoPlayer extends VideoView implements VideoPlayer { + + private enum PlaybackState { + STOPPED, PAUSED, PLAYING + } + + private MediaController mMediaController; + private PlaybackState mPlaybackState; + private final List mVideoPlayerCallbacks = new ArrayList(1); + + public SampleVideoPlayer(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + public SampleVideoPlayer(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public SampleVideoPlayer(Context context) { + super(context); + init(); + } + + private void init() { + mPlaybackState = PlaybackState.STOPPED; + mMediaController = new MediaController(getContext()); + mMediaController.setAnchorView(this); + enablePlaybackControls(); + + // Set OnCompletionListener to notify our callbacks when the video is completed. + super.setOnCompletionListener(new OnCompletionListener() { + + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + // Reset the MediaPlayer. + // This prevents a race condition which occasionally results in the media + // player crashing when switching between videos. + disablePlaybackControls(); + mediaPlayer.reset(); + mediaPlayer.setDisplay(getHolder()); + enablePlaybackControls(); + mPlaybackState = PlaybackState.STOPPED; + + for (PlayerCallback callback : mVideoPlayerCallbacks) { + callback.onCompleted(); + } + } + }); + + // Set OnErrorListener to notify our callbacks if the video errors. + super.setOnErrorListener(new OnErrorListener() { + + @Override + public boolean onError(MediaPlayer mp, int what, int extra) { + mPlaybackState = PlaybackState.STOPPED; + for (PlayerCallback callback : mVideoPlayerCallbacks) { + callback.onError(); + } + + // Returning true signals to MediaPlayer that we handled the error. This will + // prevent the completion handler from being called. + return true; + } + }); + } + + @Override + public void setOnCompletionListener(OnCompletionListener listener) { + // The OnCompletionListener can only be implemented by SampleVideoPlayer. + throw new UnsupportedOperationException(); + } + + @Override + public void setOnErrorListener(OnErrorListener listener) { + // The OnErrorListener can only be implemented by SampleVideoPlayer. + throw new UnsupportedOperationException(); + } + + // Methods implementing the VideoPlayer interface. + @Override + public void play() { + start(); + } + + @Override + public void start() { + super.start(); + PlaybackState oldPlaybackState = mPlaybackState; + mPlaybackState = PlaybackState.PLAYING; + switch (oldPlaybackState) { + case STOPPED: + for (PlayerCallback callback : mVideoPlayerCallbacks) { + callback.onPlay(); + } + break; + case PAUSED: + for (PlayerCallback callback : mVideoPlayerCallbacks) { + callback.onResume(); + } + break; + default: + // Already playing; do nothing. + break; + } + } + + @Override + public void pause() { + super.pause(); + mPlaybackState = PlaybackState.PAUSED; + for (PlayerCallback callback : mVideoPlayerCallbacks) { + callback.onPause(); + } + } + + @Override + public void stopPlayback() { + super.stopPlayback(); + mPlaybackState = PlaybackState.STOPPED; + } + + @Override + public void disablePlaybackControls() { + setMediaController(null); + } + + @Override + public void enablePlaybackControls() { + setMediaController(mMediaController); + } + + @Override + public void addPlayerCallback(PlayerCallback callback) { + mVideoPlayerCallbacks.add(callback); + } + + @Override + public void removePlayerCallback(PlayerCallback callback) { + mVideoPlayerCallbacks.remove(callback); + } +} diff --git a/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/samplevideoplayer/VideoPlayer.java b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/samplevideoplayer/VideoPlayer.java new file mode 100644 index 00000000..a3258eb6 --- /dev/null +++ b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/samplevideoplayer/VideoPlayer.java @@ -0,0 +1,95 @@ +// Copyright 2014 Google Inc. All Rights Reserved. + +package com.google.ads.interactivemedia.v3.samples.samplevideoplayer; + +/** + * Interface definition for controlling video playback. + */ +public interface VideoPlayer { + + /** + * Interface for alerting caller of major video events. + */ + public interface PlayerCallback { + + /** + * Called when the current video starts playing from the beginning. + */ + void onPlay(); + + /** + * Called when the current video pauses playback. + */ + void onPause(); + + /** + * Called when the current video resumes playing from a paused state. + */ + void onResume(); + + /** + * Called when the current video has completed playback to the end of the video. + */ + void onCompleted(); + + /** + * Called when an error occurs during video playback. + */ + void onError(); + } + + /** + * Play the currently loaded video from its current position. + */ + void play(); + + /** + * Pause the currently loaded video. + */ + void pause(); + + /** + * Get the playback progress state (milliseconds) of the current video. + */ + int getCurrentPosition(); + + /** + * Progress the currently loaded video to the given position (milliseconds). + */ + void seekTo(int videoPosition); + + /** + * Get the total length of the currently loaded video in milliseconds. + */ + int getDuration(); + + /** + * Stop playing the currently loaded video. + */ + void stopPlayback(); + + /** + * Prevent the media controller (playback controls) from appearing. + */ + void disablePlaybackControls(); + + /** + * Allow the media controller (playback controls) to appear when appropriate. + */ + void enablePlaybackControls(); + + /** + * Set the URL or path of the video to play. + */ + void setVideoPath(String videoUrl); + + /** + * Provide the player with a callback for major video events (pause, complete, resume, etc). + */ + void addPlayerCallback(PlayerCallback callback); + + /** + * Remove a player callback from getting notified on video events. + */ + void removePlayerCallback(PlayerCallback callback); +} diff --git a/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/MyActivity.java b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/MyActivity.java new file mode 100644 index 00000000..618e13a4 --- /dev/null +++ b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/MyActivity.java @@ -0,0 +1,252 @@ +package com.google.ads.interactivemedia.v3.samples.videoplayerapp; + +import android.content.res.Configuration; +import android.os.Build; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.ActionBarActivity; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; + +/** + * Main Activity. + */ +public class MyActivity extends ActionBarActivity + implements VideoListFragment.OnVideoSelectedListener { + + private static final String VIDEO_PLAYLIST_FRAGMENT_TAG = "video_playlist_fragment_tag"; + private static final String VIDEO_EXAMPLE_FRAGMENT_TAG = "video_example_fragment_tag"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_my); + + // The video list fragment won't exist for phone layouts, so add it dynamically so we can + // .replace() it once the user selects a video. + FragmentManager fragmentManager = getSupportFragmentManager(); + if (fragmentManager.findFragmentByTag(VIDEO_PLAYLIST_FRAGMENT_TAG) == null) { + VideoListFragment videoListFragment = new VideoListFragment(); + getSupportFragmentManager().beginTransaction() + .add(R.id.video_example_container, videoListFragment, + VIDEO_PLAYLIST_FRAGMENT_TAG) + .commit(); + } + + orientAppUi(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.my, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + if (id == R.id.action_settings) { + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onConfigurationChanged(Configuration configuration) { + super.onConfigurationChanged(configuration); + orientAppUi(); + } + + private void orientAppUi() { + int orientation = getResources().getConfiguration().orientation; + boolean isLandscape = (orientation == Configuration.ORIENTATION_LANDSCAPE); + // Hide the non-video content when in landscape so the video is as large as possible. + FragmentManager fragmentManager = getSupportFragmentManager(); + VideoFragment videoFragment = (VideoFragment) fragmentManager + .findFragmentByTag(VIDEO_EXAMPLE_FRAGMENT_TAG); + + if (videoFragment != null) { + Fragment videoListFragment = fragmentManager.findFragmentByTag( + VIDEO_PLAYLIST_FRAGMENT_TAG); + // If the video playlist is onscreen (tablets) then hide that fragment. + if (videoListFragment != null) { + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + if (isLandscape) { + fragmentTransaction.hide(videoListFragment); + } else { + fragmentTransaction.show(videoListFragment); + } + fragmentTransaction.commit(); + } + videoFragment.makeFullscreen(isLandscape); + if (isLandscape) { + hideStatusBar(); + } else { + showStatusBar(); + } + } + } + + @Override + public void onVideoSelected(VideoItem videoItem) { + VideoFragment videoFragment = (VideoFragment) + getSupportFragmentManager().findFragmentByTag(VIDEO_EXAMPLE_FRAGMENT_TAG); + + // Add the video fragment if it's missing (phone form factor), but only if the user + // manually selected the video. + if (videoFragment == null) { + VideoListFragment videoListFragment = (VideoListFragment) getSupportFragmentManager() + .findFragmentByTag(VIDEO_PLAYLIST_FRAGMENT_TAG); + int videoPlaylistFragmentId = videoListFragment.getId(); + + videoFragment = new VideoFragment(); + getSupportFragmentManager() + .beginTransaction() + .replace(videoPlaylistFragmentId, videoFragment, VIDEO_EXAMPLE_FRAGMENT_TAG) + .addToBackStack(null) + .commit(); + } + videoFragment.loadVideo(videoItem); + orientAppUi(); + } + + private void hideStatusBar() { + if (Build.VERSION.SDK_INT >= 16) { + getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN); + getSupportActionBar().hide(); + } + } + + private void showStatusBar() { + if (Build.VERSION.SDK_INT >= 16) { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + getSupportActionBar().show(); + } + } + + /** + * The main fragment for displaying video content. + */ + public static class VideoFragment extends Fragment { + + private VideoPlayerController mVideoPlayerController; + private VideoItem mVideoItem; + private TextView mVideoTitle; + private LinearLayout mVideoExampleLayout; + + @Override + public void onActivityCreated(Bundle bundle) { + super.onActivityCreated(bundle); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_video, container, false); + initUi(rootView); + + return rootView; + } + + private void loadVideo(VideoItem videoItem) { + if (mVideoPlayerController == null) { + mVideoItem = videoItem; + return; + } + mVideoItem = videoItem; + mVideoPlayerController.setContentVideo(mVideoItem.getVideoUrl()); + mVideoPlayerController.setAdTagUrl(videoItem.getAdTagUrl()); + mVideoTitle.setText(videoItem.getTitle()); + + mVideoPlayerController.requestAndPlayAds(); + } + + private void initUi(View rootView) { + VideoPlayerWithAdPlayback mVideoPlayerWithAdPlayback = (VideoPlayerWithAdPlayback) + rootView.findViewById(R.id.videoPlayerWithAdPlayback); + View playButton = rootView.findViewById(R.id.playButton); + View playPauseToggle = rootView.findViewById(R.id.videoContainer); + ViewGroup companionAdSlot = (ViewGroup) rootView.findViewById(R.id.companionAdSlot); + mVideoTitle = (TextView) rootView.findViewById(R.id.video_title); + mVideoExampleLayout = (LinearLayout) rootView.findViewById(R.id.videoExampleLayout); + + final TextView logText = (TextView) rootView.findViewById(R.id.logText); + final ScrollView logScroll = (ScrollView) rootView.findViewById(R.id.logScroll); + + // Provide an implementation of a logger so we can output SDK events to the UI. + VideoPlayerController.Logger logger = new VideoPlayerController.Logger() { + @Override + public void log(String message) { + Log.i("ImaExample", message); + if (logText != null) { + logText.append(message); + } + if (logScroll != null) { + logScroll.post(new Runnable() { + @Override + public void run() { + logScroll.fullScroll(View.FOCUS_DOWN); + } + }); + } + } + }; + + mVideoPlayerController = new VideoPlayerController(this.getActivity(), + mVideoPlayerWithAdPlayback, playButton, playPauseToggle, + getString(R.string.ad_ui_lang), companionAdSlot, logger); + + // If we've already selected a video, load it now. + if (mVideoItem != null) { + loadVideo(mVideoItem); + } + } + + /** + * Shows or hides all non-video UI elements to make the video as large as possible. + */ + public void makeFullscreen(boolean isFullscreen) { + for (int i = 0; i < mVideoExampleLayout.getChildCount(); i++) { + View view = mVideoExampleLayout.getChildAt(i); + // If it's not the video element, hide or show it, depending on fullscreen status. + if (view.getId() != R.id.videoContainer) { + if (isFullscreen) { + view.setVisibility(View.GONE); + } else { + view.setVisibility(View.VISIBLE); + } + } + } + } + + @Override + public void onPause() { + if (mVideoPlayerController != null) { + mVideoPlayerController.savePosition(); + } + super.onPause(); + } + + @Override + public void onResume() { + if (mVideoPlayerController != null) { + mVideoPlayerController.restorePosition(); + } + super.onResume(); + } + } +} diff --git a/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoItem.java b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoItem.java new file mode 100644 index 00000000..ec072256 --- /dev/null +++ b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoItem.java @@ -0,0 +1,50 @@ +package com.google.ads.interactivemedia.v3.samples.videoplayerapp; + +import android.graphics.Bitmap; + +/** + * Information about a video playlist item that the user will select in a playlist. + */ +public final class VideoItem { + + private final Bitmap mThumbnail; + private final String mTitle; + private final String mVideoUrl; + private final String mAdTagUrl; + + public VideoItem(String videoUrl, String title, String adTagUrl, Bitmap thumbnail) { + super(); + mThumbnail = thumbnail; + mTitle = title; + mAdTagUrl = adTagUrl; + mVideoUrl = videoUrl; + } + + /** + * Returns the video thumbnail image. + */ + public Bitmap getImage() { + return mThumbnail; + } + + /** + * Returns the title of the video item. + */ + public String getTitle() { + return mTitle; + } + + /** + * Returns the URL of the content video. + */ + public String getVideoUrl() { + return mVideoUrl; + } + + /** + * Returns the ad tag for the video. + */ + public String getAdTagUrl() { + return mAdTagUrl; + } +} diff --git a/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoItemAdapter.java b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoItemAdapter.java new file mode 100644 index 00000000..103515f5 --- /dev/null +++ b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoItemAdapter.java @@ -0,0 +1,59 @@ +package com.google.ads.interactivemedia.v3.samples.videoplayerapp; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.List; + +/** + * Renders VideoItems into a GridView for displaying videos in a playlist format. + */ +public class VideoItemAdapter extends ArrayAdapter { + + private int mLayoutResourceId; + + public VideoItemAdapter(Context context, int layoutResourceId, List data) { + super(context, layoutResourceId, data); + this.mLayoutResourceId = layoutResourceId; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + VideoItemHolder videoItemHolder; + View row = convertView; + + // Check if it's recycled. + if (row == null) { + LayoutInflater inflater = LayoutInflater.from(getContext()); + row = inflater.inflate(mLayoutResourceId, parent, false); + videoItemHolder = new VideoItemHolder(); + videoItemHolder.title = (TextView) row.findViewById(R.id.videoItemText); + videoItemHolder.image = (ImageView) row.findViewById(R.id.videoItemImage); + row.setTag(videoItemHolder); + } else { + videoItemHolder = (VideoItemHolder) row.getTag(); + } + + VideoItem item = getItem(position); + + videoItemHolder.title.setText(item.getTitle()); + videoItemHolder.image.setImageBitmap(item.getImage()); + + return row; + } + + /** + * Holds the UI element equivalents of a VideoItem. + */ + private class VideoItemHolder { + + TextView title; + ImageView image; + } + +} \ No newline at end of file diff --git a/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoListFragment.java b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoListFragment.java new file mode 100644 index 00000000..f615a2e1 --- /dev/null +++ b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoListFragment.java @@ -0,0 +1,122 @@ +package com.google.ads.interactivemedia.v3.samples.videoplayerapp; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.EditText; +import android.widget.ListView; + +import java.util.ArrayList; +import java.util.List; + +/** + * Fragment for displaying a playlist of video thumbnails that the user can select from to play. + */ +public class VideoListFragment extends Fragment { + + private OnVideoSelectedListener mCallback; + + /** + * Listener called when the user selects a video from the list. + * Container activity must implement this interface. + */ + public interface OnVideoSelectedListener { + public void onVideoSelected(VideoItem videoItem); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mCallback = (OnVideoSelectedListener) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + + " must implement OnVideoSelectedListener"); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_video_list, container, false); + + final ListView listView = (ListView) rootView.findViewById(R.id.videoListView); + VideoItemAdapter videoItemAdapter = new VideoItemAdapter(rootView.getContext(), + R.layout.video_item, getVideoItems()); + listView.setAdapter(videoItemAdapter); + + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View v, int position, long id) { + if (mCallback != null) { + VideoItem selectedVideo = (VideoItem) listView.getItemAtPosition(position); + + // If applicable, prompt the user to input a custom ad tag. + if (selectedVideo.getAdTagUrl().equals(getString( + R.string.custom_ad_tag_value))) { + getCustomAdTag(selectedVideo); + } else { + mCallback.onVideoSelected(selectedVideo); + } + } + } + }); + + return rootView; + } + + private void getCustomAdTag(VideoItem originalVideoItem) { + final EditText txtUrl = new EditText(this.getActivity()); + final VideoItem videoItem = originalVideoItem; + txtUrl.setHint("VAST ad tag URL"); + + new AlertDialog.Builder(this.getActivity()) + .setTitle("Custom VAST Ad Tag URL") + .setView(txtUrl) + .setPositiveButton("OK", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + String customAdTagUrl = txtUrl.getText().toString(); + VideoItem customAdTagVideoItem = new VideoItem(videoItem.getVideoUrl(), + videoItem.getTitle(), customAdTagUrl, videoItem.getImage()); + + if (mCallback != null) { + mCallback.onVideoSelected(customAdTagVideoItem); + } + } + }) + .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + } + }) + .show(); + } + + private List getVideoItems() { + final List videoItems = new ArrayList(); + // Build our Video item objects. + Resources resources = getActivity().getResources(); + String[] videoTitles = resources.getStringArray(R.array.video_titles); + String[] videoUrls = resources.getStringArray(R.array.video_urls); + String[] adTags = resources.getStringArray(R.array.video_ad_tags); + TypedArray videoThumbnails = getActivity().getResources(). + obtainTypedArray(R.array.video_thumbnails); + + for (int i = 0; i < videoTitles.length; i++) { + Bitmap bitmap = BitmapFactory.decodeResource(getActivity().getResources(), + videoThumbnails.getResourceId(i, -1)); + videoItems.add(new VideoItem(videoUrls[i], videoTitles[i], adTags[i], bitmap)); + } + + return videoItems; + } +} diff --git a/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoPlayerController.java b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoPlayerController.java new file mode 100644 index 00000000..aa120a9e --- /dev/null +++ b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoPlayerController.java @@ -0,0 +1,307 @@ +// Copyright 2014 Google Inc. All Rights Reserved. + +package com.google.ads.interactivemedia.v3.samples.videoplayerapp; + +import android.content.Context; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; + +import com.google.ads.interactivemedia.v3.api.AdDisplayContainer; +import com.google.ads.interactivemedia.v3.api.AdErrorEvent; +import com.google.ads.interactivemedia.v3.api.AdEvent; +import com.google.ads.interactivemedia.v3.api.AdsLoader; +import com.google.ads.interactivemedia.v3.api.AdsManager; +import com.google.ads.interactivemedia.v3.api.AdsManagerLoadedEvent; +import com.google.ads.interactivemedia.v3.api.AdsRequest; +import com.google.ads.interactivemedia.v3.api.CompanionAdSlot; +import com.google.ads.interactivemedia.v3.api.ImaSdkFactory; +import com.google.ads.interactivemedia.v3.api.ImaSdkSettings; + +import java.util.ArrayList; + +/** + * Ads logic for handling the IMA SDK integration code and events. + */ +public class VideoPlayerController { + + /** + * Log interface, so we can output the log commands to the UI or similar. + */ + public interface Logger { + void log(String logMessage); + } + + // Container with references to video player and ad UI ViewGroup. + private AdDisplayContainer mAdDisplayContainer; + + // The AdsLoader instance exposes the requestAds method. + private AdsLoader mAdsLoader; + + // AdsManager exposes methods to control ad playback and listen to ad events. + private AdsManager mAdsManager; + + // Factory class for creating SDK objects. + private ImaSdkFactory mSdkFactory; + + // Ad-enabled video player. + private VideoPlayerWithAdPlayback mVideoPlayerWithAdPlayback; + + // Button the user taps to begin video playback and ad request. + private View mPlayButton; + + // VAST ad tag URL to use when requesting ads during video playback. + private String mCurrentAdTagUrl; + + // ViewGroup to render an associated companion ad into. + private ViewGroup mCompanionViewGroup; + + // Tracks if the SDK is playing an ad, since the SDK might not necessarily use the video + // player provided to play the video ad. + private boolean mIsAdPlaying; + + // View that handles taps to toggle ad pause/resume during video playback. + private View mPlayPauseToggle; + + // View that we can write log messages to, to display in the UI. + private Logger mLog; + + // Inner class implementation of AdsLoader.AdsLoaderListener. + private class AdsLoadedListener implements AdsLoader.AdsLoadedListener { + /** + * An event raised when ads are successfully loaded from the ad server via AdsLoader. + */ + @Override + public void onAdsManagerLoaded(AdsManagerLoadedEvent adsManagerLoadedEvent) { + // Ads were successfully loaded, so get the AdsManager instance. AdsManager has + // events for ad playback and errors. + mAdsManager = adsManagerLoadedEvent.getAdsManager(); + + // Attach event and error event listeners. + mAdsManager.addAdErrorListener(new AdErrorEvent.AdErrorListener() { + /** + * An event raised when there is an error loading or playing ads. + */ + @Override + public void onAdError(AdErrorEvent adErrorEvent) { + log("Ad Error: " + adErrorEvent.getError().getMessage()); + resumeContent(); + } + }); + mAdsManager.addAdEventListener(new AdEvent.AdEventListener() { + /** + * Responds to AdEvents. + */ + @Override + public void onAdEvent(AdEvent adEvent) { + log("Event: " + adEvent.getType()); + + // These are the suggested event types to handle. For full list of all ad + // event types, see the documentation for AdEvent.AdEventType. + switch (adEvent.getType()) { + case LOADED: + // AdEventType.LOADED will be fired when ads are ready to be + // played. AdsManager.start() begins ad playback. This method is + // ignored for VMAP or ad rules playlists, as the SDK will + // automatically start executing the playlist. + mAdsManager.start(); + break; + case CONTENT_PAUSE_REQUESTED: + // AdEventType.CONTENT_PAUSE_REQUESTED is fired immediately before + // a video ad is played. + pauseContent(); + break; + case CONTENT_RESUME_REQUESTED: + // AdEventType.CONTENT_RESUME_REQUESTED is fired when the ad is + // completed and you should start playing your content. + resumeContent(); + break; + case PAUSED: + mIsAdPlaying = false; + break; + case RESUMED: + mIsAdPlaying = true; + break; + case ALL_ADS_COMPLETED: + if (mAdsManager != null) { + mAdsManager.destroy(); + mAdsManager = null; + } + break; + default: + break; + } + } + }); + mAdsManager.init(); + } + } + + public VideoPlayerController(Context context, + VideoPlayerWithAdPlayback videoPlayerWithAdPlayback, View playButton, + View playPauseToggle, String language, ViewGroup companionViewGroup, Logger log) { + mVideoPlayerWithAdPlayback = videoPlayerWithAdPlayback; + mPlayButton = playButton; + mPlayPauseToggle = playPauseToggle; + mIsAdPlaying = false; + mCompanionViewGroup = companionViewGroup; + mLog = log; + + // Create an AdsLoader and optionally set the language. + ImaSdkSettings imaSdkSettings = new ImaSdkSettings(); + imaSdkSettings.setLanguage(language); + mSdkFactory = ImaSdkFactory.getInstance(); + mAdsLoader = mSdkFactory.createAdsLoader(context, imaSdkSettings); + + mAdsLoader.addAdErrorListener(new AdErrorEvent.AdErrorListener() { + /** + * An event raised when there is an error loading or playing ads. + */ + @Override + public void onAdError(AdErrorEvent adErrorEvent) { + log("Ad Error: " + adErrorEvent.getError().getMessage()); + } + }); + + mAdsLoader.addAdsLoadedListener(new VideoPlayerController.AdsLoadedListener()); + + mVideoPlayerWithAdPlayback.setOnContentCompleteListener( + new VideoPlayerWithAdPlayback.OnContentCompleteListener() { + /** + * Event raised by VideoPlayerWithAdPlayback when content video is complete. + */ + @Override + public void onContentComplete() { + mAdsLoader.contentComplete(); + } + }); + + // When Play is clicked, request ads and hide the button. + mPlayButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + requestAndPlayAds(); + } + }); + } + + private void log(String message) { + if (mLog != null) { + mLog.log(message + "\n"); + } + } + + private void pauseContent() { + mVideoPlayerWithAdPlayback.pauseContentForAdPlayback(); + mIsAdPlaying = true; + setPlayPauseOnAdTouch(); + } + + private void resumeContent() { + mVideoPlayerWithAdPlayback.resumeContentAfterAdPlayback(); + mIsAdPlaying = false; + removePlayPauseOnAdTouch(); + } + + /** + * Set the ad tag URL the player should use to request ads when playing a content video. + */ + public void setAdTagUrl(String adTagUrl) { + mCurrentAdTagUrl = adTagUrl; + } + + /** + * Request and subsequently play video ads from the ad server. + */ + public void requestAndPlayAds() { + if (mCurrentAdTagUrl == null || mCurrentAdTagUrl == "") { + log("No VAST ad tag URL specified"); + resumeContent(); + return; + } + + // Since we're switching to a new video, tell the SDK the previous video is finished. + if (mAdsManager != null) { + mAdsManager.destroy(); + } + mAdsLoader.contentComplete(); + + mPlayButton.setVisibility(View.GONE); + mAdDisplayContainer = mSdkFactory.createAdDisplayContainer(); + mAdDisplayContainer.setPlayer(mVideoPlayerWithAdPlayback.getVideoAdPlayer()); + mAdDisplayContainer.setAdContainer(mVideoPlayerWithAdPlayback.getAdUiContainer()); + + // Set up spots for companions. + CompanionAdSlot companionAdSlot = mSdkFactory.createCompanionAdSlot(); + companionAdSlot.setContainer(mCompanionViewGroup); + companionAdSlot.setSize(728, 90); + ArrayList companionAdSlots = new ArrayList(); + companionAdSlots.add(companionAdSlot); + mAdDisplayContainer.setCompanionSlots(companionAdSlots); + + // Create the ads request. + AdsRequest request = mSdkFactory.createAdsRequest(); + request.setAdTagUrl(mCurrentAdTagUrl); + request.setAdDisplayContainer(mAdDisplayContainer); + request.setContentProgressProvider(mVideoPlayerWithAdPlayback.getContentProgressProvider()); + + // Request the ad. After the ad is loaded, onAdsManagerLoaded() will be called. + mAdsLoader.requestAds(request); + } + + /** + * Touch to toggle play/pause during ad play instead of seeking. + */ + private void setPlayPauseOnAdTouch() { + // Use AdsManager pause/resume methods instead of the video player pause/resume methods + // in case the SDK is using a different, SDK-created video player for ad playback. + mPlayPauseToggle.setOnTouchListener( + new View.OnTouchListener() { + public boolean onTouch(View view, MotionEvent event) { + // If an ad is playing, touching it will toggle playback. + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (mIsAdPlaying) { + mAdsManager.pause(); + } else { + mAdsManager.resume(); + } + return true; + } else { + return false; + } + } + } + ); + } + + /** + * Remove the play/pause on touch behavior. + */ + private void removePlayPauseOnAdTouch() { + mPlayPauseToggle.setOnTouchListener(null); + } + + /** + * Set metadata about the content video. In more complex implementations, this might + * more than just a URL and could trigger additional decisions regarding ad tag selection. + */ + public void setContentVideo(String videoPath) { + mVideoPlayerWithAdPlayback.setContentVideoPath(videoPath); + } + + /** + * Save position of the video, whether content or ad. Can be called when the app is + * paused, for example. + */ + public void savePosition() { + mVideoPlayerWithAdPlayback.savePosition(); + } + + /** + * Restore the previously saved progress location of the video. Can be called when + * the app is resumed. + */ + public void restorePosition() { + mVideoPlayerWithAdPlayback.restorePosition(); + } +} diff --git a/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoPlayerWithAdPlayback.java b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoPlayerWithAdPlayback.java new file mode 100644 index 00000000..c1f80d3a --- /dev/null +++ b/AdvancedExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoPlayerWithAdPlayback.java @@ -0,0 +1,265 @@ +// Copyright 2014 Google Inc. All Rights Reserved. + +package com.google.ads.interactivemedia.v3.samples.videoplayerapp; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.Log; +import android.view.ViewGroup; +import android.widget.RelativeLayout; + +import com.google.ads.interactivemedia.v3.api.player.ContentProgressProvider; +import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer; +import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate; +import com.google.ads.interactivemedia.v3.samples.samplevideoplayer.VideoPlayer; + +import java.util.ArrayList; +import java.util.List; + +/** + * Video player that can play content video and ads. + */ +public class VideoPlayerWithAdPlayback extends RelativeLayout { + + /** Interface for alerting caller of video completion. */ + public interface OnContentCompleteListener { + public void onContentComplete(); + } + + // The wrapped video player. + private VideoPlayer mVideoPlayer; + + // The SDK will render ad playback UI elements into this ViewGroup. + private ViewGroup mAdUiContainer; + + // Used to track if the current video is an ad (as opposed to a content video). + private boolean mIsAdDisplayed; + + // Used to track the current content video URL to resume content playback. + private String mContentVideoUrl; + + // The saved position in the content to resume to after ad playback. + private int mSavedContentVideoPosition; + + // Called when the content is completed. + private OnContentCompleteListener mOnContentCompleteListener; + + // VideoAdPlayer interface implementation for the SDK to send ad play/pause type events. + private VideoAdPlayer mVideoAdPlayer; + + // ContentProgressProvider interface implementation for the SDK to check content progress. + private ContentProgressProvider mContentProgressProvider; + + private final List mAdCallbacks = + new ArrayList(1); + + public VideoPlayerWithAdPlayback(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public VideoPlayerWithAdPlayback(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public VideoPlayerWithAdPlayback(Context context) { + super(context); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + init(); + } + + private void init() { + mIsAdDisplayed = false; + mSavedContentVideoPosition = 0; + mVideoPlayer = (VideoPlayer) this.getRootView().findViewById(R.id.videoPlayer); + mAdUiContainer = (ViewGroup) this.getRootView().findViewById(R.id.adUiContainer); + + // Define VideoAdPlayer connector. + mVideoAdPlayer = new VideoAdPlayer() { + @Override + public void playAd() { + mIsAdDisplayed = true; + mVideoPlayer.play(); + } + + @Override + public void loadAd(String url) { + mIsAdDisplayed = true; + mVideoPlayer.setVideoPath(url); + } + + @Override + public void stopAd() { + mVideoPlayer.stopPlayback(); + } + + @Override + public void pauseAd() { + mVideoPlayer.pause(); + } + + @Override + public void resumeAd() { + playAd(); + } + + @Override + public void addCallback(VideoAdPlayerCallback videoAdPlayerCallback) { + mAdCallbacks.add(videoAdPlayerCallback); + } + + @Override + public void removeCallback(VideoAdPlayerCallback videoAdPlayerCallback) { + mAdCallbacks.remove(videoAdPlayerCallback); + } + + @Override + public VideoProgressUpdate getAdProgress() { + if (!mIsAdDisplayed || mVideoPlayer.getDuration() <= 0) { + return VideoProgressUpdate.VIDEO_TIME_NOT_READY; + } + return new VideoProgressUpdate(mVideoPlayer.getCurrentPosition(), + mVideoPlayer.getDuration()); + } + }; + + mContentProgressProvider = new ContentProgressProvider() { + @Override + public VideoProgressUpdate getContentProgress() { + if (mIsAdDisplayed || mVideoPlayer.getDuration() <= 0) { + return VideoProgressUpdate.VIDEO_TIME_NOT_READY; + } + return new VideoProgressUpdate(mVideoPlayer.getCurrentPosition(), + mVideoPlayer.getDuration()); + } + }; + + // Set player callbacks for delegating major video events. + mVideoPlayer.addPlayerCallback(new VideoPlayer.PlayerCallback() { + @Override + public void onPlay() { + if (mIsAdDisplayed) { + for (VideoAdPlayer.VideoAdPlayerCallback callback : mAdCallbacks) { + callback.onPlay(); + } + } + } + + @Override + public void onPause() { + if (mIsAdDisplayed) { + for (VideoAdPlayer.VideoAdPlayerCallback callback : mAdCallbacks) { + callback.onPause(); + } + } + } + + @Override + public void onResume() { + if (mIsAdDisplayed) { + for (VideoAdPlayer.VideoAdPlayerCallback callback : mAdCallbacks) { + callback.onResume(); + } + } + } + + @Override + public void onError() { + if (mIsAdDisplayed) { + for (VideoAdPlayer.VideoAdPlayerCallback callback : mAdCallbacks) { + callback.onError(); + } + } + } + + @Override + public void onCompleted() { + if (mIsAdDisplayed) { + for (VideoAdPlayer.VideoAdPlayerCallback callback : mAdCallbacks) { + callback.onEnded(); + } + } else { + // Alert an external listener that our content video is complete. + if (mOnContentCompleteListener != null) { + mOnContentCompleteListener.onContentComplete(); + } + } + } + }); + } + + /** + * Set a listener to be triggered when the content (non-ad) video completes. + */ + public void setOnContentCompleteListener(OnContentCompleteListener listener) { + mOnContentCompleteListener = listener; + } + + /** + * Set the path of the video to be played as content. + */ + public void setContentVideoPath(String contentVideoUrl) { + mContentVideoUrl = contentVideoUrl; + } + + /** + * Save the playback progress state of the currently playing video. + */ + public void savePosition() { + mSavedContentVideoPosition = mVideoPlayer.getCurrentPosition(); + } + + /** + * Restore the currently loaded video to its previously saved playback progress state. + */ + public void restorePosition() { + mVideoPlayer.seekTo(mSavedContentVideoPosition); + } + + /** + * Pause the currently playing content video in preparation for an ad to play, and disables + * the media controller. + */ + public void pauseContentForAdPlayback() { + mVideoPlayer.disablePlaybackControls(); + savePosition(); + mVideoPlayer.stopPlayback(); + } + + /** + * Resume the content video from its previous playback progress position after + * an ad finishes playing. Re-enables the media controller. + */ + public void resumeContentAfterAdPlayback() { + if (mContentVideoUrl == null || mContentVideoUrl.isEmpty()) { + Log.w("ImaExample", "No content URL specified."); + return; + } + mIsAdDisplayed = false; + mVideoPlayer.setVideoPath(mContentVideoUrl); + mVideoPlayer.enablePlaybackControls(); + restorePosition(); + mVideoPlayer.play(); + } + + /** + * Returns the UI element for rendering video ad elements. + */ + public ViewGroup getAdUiContainer() { + return mAdUiContainer; + } + + /** + * Returns an implementation of the SDK's VideoAdPlayer interface. + */ + public VideoAdPlayer getVideoAdPlayer() { + return mVideoAdPlayer; + } + + public ContentProgressProvider getContentProgressProvider() { + return mContentProgressProvider; + } +} diff --git a/AdvancedExample/app/src/main/res/drawable-hdpi/ic_action_play_over_video.png b/AdvancedExample/app/src/main/res/drawable-hdpi/ic_action_play_over_video.png new file mode 100644 index 0000000000000000000000000000000000000000..d56941071a8e53bf921f29e153673f9fad1d75c8 GIT binary patch literal 716 zcmV;-0yF)IP)17iFbsxVUKs!epaZZ# z1}J@J0Wv@q=m1II$pFcF>3cFjvj79Y01S{yJ-O%ef$<+)Ncrw`Jb)#AmSs!E^A;>v zFl+cOmEG_62p$PY2oiwA^r`}BK^l;o@B8(`5Fn>BkPSJm0wi(;Iop!)EgjE6UWHdJ z%{V&AoQsHDOp)R71#&bc;u|`jlk?(?mf%P=FcwLq9T7tk$59goj0YeE$T!IaB(>0& zk`AU1bqAwFfD{*8Vq)kIFl(*tq`+gxEk%sr)>d!V%%8ZKN=Jxp%IQDpMq)^LF{bl9 zBnnqb^C_I~A(30}@tm^vsZLk4#o3Ky->wF9<=ozWP*`TMBMt|$=?UAl@$9Dx-~UC* zMFI*-DKd#b#ttdi(n<~6xE+4lu3xg*2)<|$*wFK8U>_rZ$zOtOEO=Z6U(^Ut$k;Jo zS~!3@_LLuy!FXmn>>J+~frKURP;H}#gqGD#CqKwGOXgUIK*$~IE|C$DOk+%CLLlI( zOxO6WeW+YW6nh7+qYRf4U~Fq|JfIECjr~A=)Fu&_5-)wusbDQxcL{Y;V*!)%Ol_sC zbdF^CxRxmQG$ zjKHer0I9hs*!BR}sK4ntFW7GSmfOmv4jI6W96wt0w}bVVjKGL`9r|n3#ts(U@pVoQ)(ZPc(6i z8k}N`MvWQ78F(rhG(?6FnFXYo>28{yZ}%O}TvdDT_5P?j=iW=V`8=UNc_}`JbG!ST zs@lK(TWkH+P**sB$A`cEY%Y53cQ}1&6`x-M$Cz&{o9bLU^M-%^mY?+vedlvt$RT-^ zu|w7}IaWaljBq#|I%Mpo!Wc2bbZF3KF9|D%wZe{YFM=hJAv$>j>nhx`=Wis#KG!cJA5x!4)f) zezMz1?Vn$GnZNjbFXH(pK83nn!^3=+^*kTTs5rV9Dq^XS(IKO!mKt5!dSmb3IVCxZ z8TTk5IE)F1V29$G7v#j9d-hy&_pdg8?kT4)zqr>?`}I%W>(?GO%*C&}?Fp|bI*~2&KZ$%^B6R&1~2kA{`CWy+>F-x=z-f{_&vyu_3yp{jtw(*syi% zu3t2|4{c~LJXRt2m>rMg2V_kLltCZ<`m>qcI?BPP?6hf``|e!rZEFszeYQ3f-*nAS zZ+h1$mFwy+7156lkB(k6)!1fUbJCxgIBK38$jj5cC$r&YXN)nr#PY=tJaLc?C_o?j+8H3Q>891JJ9&$l-r+-SG#q)*;r52% z@nlKflb65o%s*Jt)!pw1k{vIoQIvoJ0Y&Msiw0X!qJ)_47G*?aJ6bJFLh_4b$5&1k5wN>du*>6#i7R9T8; z7>EHOV=ue7mo77SJPwER4(A+s?n0JjYK)b}Om6n>ke?0JR=jTI+RFBg_iwb7k%n*2 zR_M0DJ9x+0zxba4(B1y^JQ_Nj6dlP5PGXvSq8fF#mxrFYj3d9(V#jJwt+IqU9+8+D z6C6Us1OI$d8OF!3+Hm1 zW5in zXV^%U35HooOpSmeqlG6e0kUMYNonKp1vr|My9}4-WO+uOxe_c-o&}%voNYHkqtle% z5yQ_^oozSUUNu30EQSAl!Q%(%3G1NXENSMjCL*Vx-Td2~rk(}d z8pT!HZe>1r5EGuz`pgsg@^yQEi=BIa#meLq0!?{TZ}q#}=7UC9_l=w|wv+pP!g4#! zRys6EN$Jv}#U47$k&)pDzvks}LGfPku6P9p!56Py)~1)W(11n7n}`Wx!=;_JTiu#d zpCqx=hEk@t4sp?!j{W}wP@V-=Pd=T^>6IKBy;#mLA7hCe{V7B3@I7Ipa}L`MbF|YQ z)$BNWsiEnoNHrtJli|n8cOnn4NyF=8MbVxgof0>Uv%wM_j94a;8(LMjlL~E(99gJ*2%JtNtAkD@j;^ za~Y~&j6uY{=Rv5S4joH*RW_m9N{ZSN0HhAwFyJNok zS9kx$>wMf%tUi&Eb`6u0lWJ|k?A-42(lp2UmS(PrAc(24wexRiHUieMwf$o%m6$xs zp#-SdBUu2D5`v;(9-sm&kN2M74c&AvKe_v@tQ|dzJ2qSgQHpnUP(iQ?J%Il;Jdyp# z7}cpq6Kdm+FS~zS4Eo;fuO=DFP*UlpO|_CNt5&NUqBvQWxmg7#ARvMf=%#H@p%RZ` zjK$hMbNb+vVP3UlkfIt&ptJ<00Ic{Ka+lF+&w;OEs1O2#V8~O|R*Gq9TIgM&UqM&bZOXBwnbC? zDr))NR&g>lwVgcmnx`K1$)PTTw3m}-T11^ZkY{}jQ@lGD$XzJIcVFkYBBW=o_}TUU zt@yd{Jz;@~72x#!RG(#ira6}v-*J#<{@@^OI-Q2T^}=IKLubsa&V-%WwlF1s7fz~u zMdQTV7SnRet#^`VO0V7H(?59X{uy+S`(sorO@2-+qioUdo9+6r4#|jb=?t50oh42R z{}I>Krut|YKkOc|O|M>y#(3YA;I(i+MiHSfwbJA$jIUr$Y2i|u)*>@2eUYk`j4C5r z>61dKu!AqM_E7#DoDzbd-bfT%AYXUUB{SS|{b{`5^?wz1{PVQgTlvyqOX8(#GTz(U zNPhnj>$lC`xaD56`TjW&uW8p~qikP*F8kHFM0frzdk%UNGjb1O$%uLK`0-)2UsZ3L z#+j+CI_8k4VslL%$aVR@joX>M-@odbX!os$xY$HDIOCokY?{Q0v2kQErf|ZlN>D9w zC+2}E&?rDdi#%))$p%P4C_xGXu=@U~_<|V4L|{>TP$XBp$5pCPXLzK3!;gP>7=QNi zkNOur`>xY=@VSpB#LsN9JKpOz({ANcdv>?K+D_*_HZ<;9>kplj^Ph5!e&&a#?(3vK z_Q@}D_M5kGcx^AuaI~qKYUnb1Mj-n;MURXa)+x7~e2gbMW|gw?5Rg zTOMlo>6zIJ$VNVgn(@kTSL0eP)nR35IHpoHM2W#h6cNmTm@-9`dFJ$;k(S`7Lg@RY zp!hNmb9un!O4Wt05ANDGirv(B14gW| zwjP}C9bK{J`qZ_S2o)b`RonR-b8~y8)$H0`+gg6>#^wu8eCp9xA9B>>8(KRizI?+^ zAJ#i>*({qM-c4gBB~5dzg(wj!HA`hkh!aDl5>u&J;>2K#Ax2)2wt|L!9X;(=*jy!`r4_FhCBoRxNjXNv(~jGQ|%<}%K6RimaBJcP0v}oCgRN3B;oiM)opj? zXm;;tv3q-yy}NqMOr^~3&1lW$w3}UK_IT2sCrkYx5$&6e2A%g;QZUX~A&L!2rFd0p z5%men@^zN_Xw2|v%*c2|wQfkN4r6u&k;LxYY+w3{KY#cie)!iz>(yAgt=&-+Sy2V& z9BJxI+VMKQ%dvY~x>gmEijj3ss_*NAT(8d1@DQ6e&#Ln&6Qk>wHrh>;V2nvomC`8& z(w?`?*_^3u-TJrMzv2~7dH(XLJvUOXk4U8oW6Ol)YsawhIB{GdvIzu1hzMTrE)cvB z%2GxMpaF89<9uF(?cfN(BNR?wwWvCZ6e62+G_{$+;`yjgLj{(^z*zzwd;K3RElb*%=??P zm+lLY0@Y}^kVdMYX5M)YJ~8h=i(S{q#NfU0xPTao4WPDQL=Y_;vg=p%iay1_`<0Ga zMG&<(pOU+bI2u9_g8IJBTqGX*3@G$Zc`pj0f@)vd2?Aj`ms>DHg>;w~p}HXV(*VJX zphd;fht9qL3E)D8h$$A;SGl22Ygv>`iU=A)z=1ZYN$|2`*$`R)?KD>$tw_e9h_x~eX_udS~Q%yz?48i*aIa+_wx|j{B zsG7mwZ)6M3dmvgMC3K-66;ML(9o2xU!F8+qF)>v{1;ip)6v_I)6law|rd_Dx2oV|n z(Qm_PUnTTuKFG)w%s|)lS!w~Lm$k|Al=0djocyHU;>1H=!N}0E0lSV^b2^6~^lUco zyoH+|_!li3#euHd4TJS8=CLaHG9H8g&h3Xm z#>BkpUBAmae(#)qO3)ZMG3irM=5IzA^s+)w86=tIMT{&?Awux<(k2>U#n`c&@Z?u= z%=#BoO-9Nc^?)hz*YW~~tU8rLR-MZBJsY_7fp2r~mY>q-O;L%5Fp?}V6CK=F(18U3 znxB8ZR0TT{)T64RDt!+yFgp!JXGP0|It0Hz2Em#YfRv>O>8A?J=Sz!nq<|{&mW=?~ zDQT{S6PH0|jwy37t+0Ob6izz)JdRlNEUbyk>-K?}FOT=Dj9SuS_0nTFd+A^D?Bo83 zTkicXcW=IuZoZd(Dl;&#`LI;_s?e;OH9quf?*XuV0O$Qh0j~HWKpA|PXV4&b2zs z@W5<)dtovIRZ@gvsi$^s;v05(XwF3$lJ;wzYfE`46fnT7>!qt|hWHRE>yQP)i8= zVbC|O{Ud6%kwGcch>>|pE-=?cW;TDR0lE5Nw7l66lr-zIYT3bj^ujCn$b0{ZO;gwK z#}}W(*T3~in$6ZCpbB98pftPTo;!K>U;H*7_}t4m;;4i9#^2t`pS<=jsnx198);d3 z-M6Mx{7-c0A-jhJQ`5mBy8TBnfbr2~sER5E5oz}=so34cg)GYarRWi8w#W$%G{?Z*4xDb#LX1B1 zg!4G{m~*)H_J8J^SNt`XU-fxjea`>p_$Qyn*Dn18*WdPCp8oWw^XU)%kfRQHMgfQh z1j_ua@O4G%QK;&YH3Y9(q!hkgOUCkcVH5N0Ug(EPX%H6qCfPqg))qrd#ec^47dBu- z=sRkmjGS>3K(tfRTo;zCXO-74hV;y1!vCN}v|w?AWR$YpYXs@Dr?iNLKD9s|2)0aHY!TKTYhwMI z7b#54h!H6rUU9+xnL$g6h?t?Li5guXPY1g)$bI$~rHWP%QkYJ6Y-U^0C(@*$ruN2*zn0QRBOeVpgMFbT%k!Dn1*u#%J^y)enX1K;0~ z%3Q zP(b%}P!Loj6M{v96(Qa~K!bq-V-P89U_K)0zHC_F#L==3IPh2hHG6&?rxvQ%|EljR zfGIDyu=rIrl1dyjuMfwuh?pXZmARwNZ?GbW;5BH5D#nN|WbGm+UGAh7_AcG>4&|{0 zrg?k@h8zm!0A|5Zo%X%g|2tBPKHHB6`~4h?I@bepDe6?^f8w zBnzfOf|j{kR5m6BLRr0$!RZ$PHSk*)tyjkws*DpyHIiiL*8o(Smx(OKT7@D&Y3OI^ zEUMtKa2*SLjt(eJsZsLsrgV`A+xL(~JN#JU6+L)gCe%VuSNbCzTr09w>eZ#779SKV z)m)@#TNVy|q3Tz_U`^7MY`l}`GU~OlQi|*cprX?tm@tIV+8kOGkaa=9Y<{N|RZ)ns zHlgnz2S%qwK9wXjest~Ux$YNNA{0?6Xpv{_mqYt8D`g&7Yb~>lX+HP&AK<=+Zl_kO z6a2g`^4=9W92GQ3e9Mk6?DlzlkIM`iOzwk*5L81TcuyYkI-<3^@49_+^XC7&N}SL1 zh$kIBxb`9+v}acfV?FQ zN#04eHe0*j{pz=zOj3#EHLrT3e)O;3xqpCWrl$e)PcD9jQ4P-8_zyZg^M7i|*kOuj znsvlwNUsy5+01^P_sqMOjXjxKwHn4)$87t-MWZZ*5Dbit4|D9vL+spsJ0JPd?{Ms) zFW^<@yqjZ=IvG%$ck_Cu9|b8CvoV%5P5IZWzs>i4`~`N+-p`7a6RbLHJ;nxtSB#Mb z`1I552=9DrYWFNZ{-=Mt;SVo5@3cmv`IZT@@>#~zCe-=qENxsn+uHfL`e?SbT3IQ_ zt~e)Lcirs_S5^X#?hDYmgV%8QQDe+?>*1&0e^BnaeZz(&D~3<)#QuUL8h*NlXgtr| z&a{_Z)o9FK_U5<0!E3N|yY1P2g%J9s*?!zF78+NSb%!ix)tbQ09oO&|U$~Bwk35^- zec9VN^xz{043e^xD}WEmzh8d^-~Pd8**bEfd+I?HuO~n4SksoN8LRPUy={E<@BjRMUh?X71Xaey>t^$&Eq2B7)u_r$ z|IQwpG52G!F$J5fRo1LqLB7iKz_!bI@27skX~+Eze|Y}IBuRp?hR7z|eA~7B<99#7 zrX4r2a_tCDUb_}Cg)g!OEVeJ5AEVRyb!9~f4OL68qhZZRP0l*>MdkxvxXeGWx$T>+ zI^X!wnYQDnwK9?i)j)eLXJU2Cw>~>R?72@MecvT7;h~2gATow_cbc)$Ws+xNSB{++ zo^tTp^y*(-Y-XF=$XyoBJnMN9+p!Qrep1)%ym_v7zZH{;u~L>T=4XP!f^?uC4ULUR zdl`>x+DVkHVd;|9#N*oubBFQEyRT#UK^0c7T}l)eEEFS)qvZl%f>#I;iCwAWb=kW0 z(e#lm51o?d>D|kgtTscVQCNDAXMAjxSX&{_Qf)T((wMHWWLbz6WpPXP0(3_SBWwI19Vx?$i6WUqP$4O|wjNbYzst$z{58`cBhm z&F(N-KeXFzo#aC|6BbC($As#B8X=}ggpDyQUp|Q>9cG$47#>TQn%T(eHA`5se7KnZ zF_dj_6NN0xS-oZ%Nj%PTpK=MC zw*4IMGls_v)mokI)Dph*pD<)7prEF|j6I$2=XF=Ua3z;BN^yt&H@G%7& zWnL7*e0S9svjSP>kuc;VCbZXUN3G7D8`G@!Qnjt=p=7yC?QH0tsa@RsuPMLj@wf-c z|LV)H$Auga+MTAU#>)eeuh_L`!qC=Ls|{m}Cy)|w6#aP}w6_-ya~9LF z{dQAPa-|&ME858gIK=}lVK7MLT~Oye&UM9y?0X=8Qmvb*)=X}iv%Me)Gqav+FWdGT zuk&#ak~?2Kzf}w)xZuKGx%+`1?Ecoq?*H@EjFm%C6OT577vWKoJB z$A^sIasm!5TGOFFGmHkKNTE7KW3nveUq1bt4Uj)!1_6BJ zU6=EoPrjVdk+pQX+j-GTpQS&&^43tT43kuRlvE8fGdYc!1|m)3WCuwlqB>NeQc0** zYE&wTj*QpuPLfJ)j2$(`sI@k@oR!^9d(3&Kd6r3*<)pooPNzq=)1%#NQ;nAsF*5VR zOYXQC;B^4*Sik--jy?J`uDj-! zSep}9YT4*SOrT2I6MF4H+EZFRPh+}^b4@i8OYk9Y&86o*Y4(`Ax1W4#tX^5m6LjZPb61LF2?qBy?B_?1YE!nej)R5c8qG`2s_uF`Cu+ z`X_$#2Ur#!Pw0WVd60fYG8A#y55LDyJ!Yt$5G6Efb<6Nr%-BTC_|llMB?%*A5%rOX z`fyBbD5g@4Ns^)P;F7zjv{t6u?k1J0kR*v#Dhair3iXjH^^qz=!xd`vm`W`oN-Wj_ zNML7~t!rRbc|9I0mUjpEgOJ9XGg2;vjDZ;b~V638P!uVuejytg~ci-I(n9#M6AR=mQG0YjoLKGPgFp(jS4Pn7UJR)Et z-8ZsqWsRLXri#f_BSeWIat3P+Q3Td1#ws={2CLGpDdvrgP#KD7 z&SnaR^#_Bsq;Xt;kyI^}iX~1WYzdHamc$tH1#Mz6f<2(WuH^s%^yXK78Gyg}{;LNA zoW%$)#R!a0wv&q%qj%+~i3^k&1jY!ljfi82Vr$~W5G6u&$Wp0VqR3*bDIWLE4Y64K ze08)CmeFrq2>QGFSDAk%Rhs}$r*rJVNuoO(~AJ!PG{T~d_i(dQ;OsQc+q&twwlJV|`Bv$N}R$K=uxCPyc!RBBXfRjRcZi5yAQk|YKj*>d`|Xw~ckP!!SW%^gsH z4oDR1AJt?S?}B;<&e0TPFsNAMQwxCt69o{uA>=K^qd1+MST3tptj8GHnN(upgb*ji zq`i%b+{{=o7ByB78@8!x_Gs&uqLOKv_6{gO2b4jbc8YT@EEzqBp!v_c?XXFx9Dq zb{!I|Nu<;4kZbyl3*LDg#$f7`nKwT9p9|2|t&fmAe64Of^c3TKI%Q?_^+uxaj|?xL zw5U4G#YlpQDngbfM)q85qt=DJt|y5nG){VqE;V8I&WBCAH+|pe@QT+};^BWB8(lGB zqe!DD7GqI`0pj%h;hm z;n?F&(5YS1X4{T?Hf24&;~ic?rDC*Zgk;*ga9b~Je`?R%gBQy3U5$!cEi-#s>T+d# zWH}Mbv|6p1R<`wiiPB32Gn*u}EQxC^LGJIR?H}~g*|#s5IQY`pJzcYP=0El5RWIen z8*k;5(^qldFJ}(enhxl1pnB_vPi5uu!@1|-9|Owd=%J>WPwQ>dkLW|!5WV<$<73Xb z{0CRJT1OpP567)vYea*J7*!3_M-nC`C)l*@dKzsw^5El5v)K$c-nf?sZ)?i>Gc=yt zg{xL=urnv{!j}h=hh{KFAjIS@=h9CpFJM%_kv_I`nBFpYHG36;j zUDrukN z^FxYD!hui|)^Nt_FnDXomP3s*RD!(HG z@3D?)H6cToH((Zy{TkSWh7~FOmNEBc7Je?cDxiIs?~RnM2*uT2|It<1X2{GkY%=tD z2(jT6fz$Hf;XN8QtP$udK6ZF4cvzu$U0u@{HmnX52-zvI=p~}DHq)Z%EPOTa7qkGp zG&jE6K2M2J_$2H|_QP?RU2M1AH~LHq%3>IsF%@AT*s3?NdEIlHun+a07*qoM6N<$f@443r~m)} literal 0 HcmV?d00001 diff --git a/AdvancedExample/app/src/main/res/drawable-mdpi/ic_launcher.png b/AdvancedExample/app/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..359047dfa4ed206e41e2354f9c6b307e713efe32 GIT binary patch literal 5237 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 literal 0 HcmV?d00001 diff --git a/AdvancedExample/app/src/main/res/drawable-xhdpi/ic_action_play_over_video.png b/AdvancedExample/app/src/main/res/drawable-xhdpi/ic_action_play_over_video.png new file mode 100644 index 0000000000000000000000000000000000000000..787bd394c92856f0859803acfd0342983ffc3ded GIT binary patch literal 1499 zcmV<11tj{3P)} z!xZs(QwqQtzi3GO0gu0UE*W75$#v_oBE{G-Y^aEp3yX*?6Az>;8wAs{zb;fW8@%VJ zVO)V={bDnliY<~qMR${2n1wm|=F-p@5{xyo3)WYnTl(mQ0#NAXh1uuC4>yQEd$fi! zSOuW@ze@bD)tT1OG9lLdHtCXLgMtC+Yl&c1W|t-_g)u(K0>76ExI+HQ^{l^Q4GWt} zh%J(DbS8y5{#f(i!RNmV27kc8mr(#fm$VkdE*SqWoiX7~^PpctC%>AN|Ht}-W3Qu< z5oPsD0T{%Fp_AW02}6|C9|d6W$|OEBIPwKb;AO~AX7>s}zdslJD`@fsO5ia^*_~U! zQsDPjzGpivl>oA=1o2?$Q~_Ak5vkc96 z6U2js69r%~i!WqtH28g}R&Lq#=N?)CV+=_jWE=t_7{6_Q=|PyL#a zqZcK%WWVb;fJ`*|4ahpc2cI>T2z-Ia3No86Xu|z|GF;DxK%X-q7e2%Xl=XCl6Eg~^ zwT{%0TatZ>@nPzL736}4v&4o4h)iu~QE(6vEa4Lyw_IV@kQ?m^7z^@#7f-wpAJ!Nj zQrkC2nfF(?v0?#Vj$Og%oVGfM4_{U-Kw|Q~^j*$T5f2vcSv2HGn+1#n*^f^h$yI%Z zk&xSn4=DTT3P)NMF!Xfxi^jRevPNpz3R05_;C-y`{rHfZzZ;GZM?rF6%>@;a|41-C zdHVKH3ih z&4l(i>y;lQMJa8Y>#Dk-BrxKu{vOQ>x0N_(8-$gf`W*XtAbw_G)x1)5;J$+(b)*51 z4-HitgD;Izl~{S#!GuGx0GNr7jQEw|H+DP+N0S!7n-{cWq@KMKfEoB~V}lOKt}W(V z5D3L*LO26_P(X<(<;LPYMf~Aq3|L)tNmW}!#L`U zC?ZF#@RI(h)(r|eEC4XEEI;^pSU~M^)#aoiH+mHy>4%wF^z-0mW*#)`@-lbokLp?t z-3hWG)9oN|Pgo+lalQ0O(wg6?JJ9#`bW`O6)iJtlPe+Jaw5OWg&5NP(feQK4NMmb$ zta&Dsm=2bT7GSDOtRwT;Mn4O1N|vwsM$E*@!ABqbyad7(p(+{-(QQ85FOU4r7J?R zh&c&e2{rN)!9$mp#ptnt!S-Uu6kGDphE46r_jkjlT09VK?*f8sJzML0Dd27;%y{01<6J;BZ8O+I+xa)bJj+@d1Ype%Lf_^Ajc#i=dDAc#@B25q-wW z8->t^+&ooGZ$4#6AP@)y0)apv5C{aqZQ-8)0|59O;E59F=NbS2002ovPDHLkV1kd< BxnBSP literal 0 HcmV?d00001 diff --git a/AdvancedExample/app/src/main/res/drawable-xhdpi/ic_launcher.png b/AdvancedExample/app/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..71c6d760f05183ef8a47c614d8d13380c8528499 GIT binary patch literal 14383 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 literal 0 HcmV?d00001 diff --git a/AdvancedExample/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/AdvancedExample/app/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4df18946442ed763bd52cf3adca31617848656fa GIT binary patch literal 19388 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 literal 0 HcmV?d00001 diff --git a/AdvancedExample/app/src/main/res/drawable/thumbnail1.jpg b/AdvancedExample/app/src/main/res/drawable/thumbnail1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9405d191dfcd6f269da47d7ec404d27154dac594 GIT binary patch literal 23299 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 + + + + + diff --git a/AdvancedExample/app/src/main/res/layout/fragment_video.xml b/AdvancedExample/app/src/main/res/layout/fragment_video.xml new file mode 100644 index 00000000..36540452 --- /dev/null +++ b/AdvancedExample/app/src/main/res/layout/fragment_video.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AdvancedExample/app/src/main/res/layout/fragment_video_list.xml b/AdvancedExample/app/src/main/res/layout/fragment_video_list.xml new file mode 100644 index 00000000..8499264f --- /dev/null +++ b/AdvancedExample/app/src/main/res/layout/fragment_video_list.xml @@ -0,0 +1,29 @@ + + + + + + + \ No newline at end of file diff --git a/AdvancedExample/app/src/main/res/layout/video_item.xml b/AdvancedExample/app/src/main/res/layout/video_item.xml new file mode 100644 index 00000000..591ecce7 --- /dev/null +++ b/AdvancedExample/app/src/main/res/layout/video_item.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/AdvancedExample/app/src/main/res/menu/my.xml b/AdvancedExample/app/src/main/res/menu/my.xml new file mode 100644 index 00000000..0777cf37 --- /dev/null +++ b/AdvancedExample/app/src/main/res/menu/my.xml @@ -0,0 +1,9 @@ + + + diff --git a/AdvancedExample/app/src/main/res/values-w820dp/dimens.xml b/AdvancedExample/app/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 00000000..63fc8164 --- /dev/null +++ b/AdvancedExample/app/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/AdvancedExample/app/src/main/res/values/arrays.xml b/AdvancedExample/app/src/main/res/values/arrays.xml new file mode 100644 index 00000000..91787e26 --- /dev/null +++ b/AdvancedExample/app/src/main/res/values/arrays.xml @@ -0,0 +1,46 @@ + + + Pre-roll, no companion ad + Pre-roll skippable with companion + Post-roll + Ad rules + Ad rules pods + VMAP + Wrapper + AdSense + Custom ad tag + + + + + + + + + + + + + + @drawable/thumbnail1 + @drawable/thumbnail1 + @drawable/thumbnail1 + @drawable/thumbnail1 + @drawable/thumbnail1 + @drawable/thumbnail1 + @drawable/thumbnail1 + @drawable/thumbnail1 + @drawable/thumbnail1 + + + + + + + + + + + + + diff --git a/AdvancedExample/app/src/main/res/values/dimens.xml b/AdvancedExample/app/src/main/res/values/dimens.xml new file mode 100644 index 00000000..b48e5d04 --- /dev/null +++ b/AdvancedExample/app/src/main/res/values/dimens.xml @@ -0,0 +1,6 @@ + + + 16dp + 16dp + 16dp + diff --git a/AdvancedExample/app/src/main/res/values/strings.xml b/AdvancedExample/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..1ed1d959 --- /dev/null +++ b/AdvancedExample/app/src/main/res/values/strings.xml @@ -0,0 +1,13 @@ + + + + IMA Advanced Example + Settings + Suggested Videos + Companion Ad Slot + en + 90 + 728 + custom + + diff --git a/AdvancedExample/app/src/main/res/values/styles.xml b/AdvancedExample/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..458266db --- /dev/null +++ b/AdvancedExample/app/src/main/res/values/styles.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/AdvancedExample/build.gradle b/AdvancedExample/build.gradle new file mode 100644 index 00000000..2027f3b5 --- /dev/null +++ b/AdvancedExample/build.gradle @@ -0,0 +1,16 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.0.0' + } +} + +allprojects { + repositories { + jcenter() + } +} diff --git a/AdvancedExample/gradle/wrapper/gradle-wrapper.properties b/AdvancedExample/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..0bffd23c --- /dev/null +++ b/AdvancedExample/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip diff --git a/AdvancedExample/gradlew b/AdvancedExample/gradlew new file mode 100644 index 00000000..91a7e269 --- /dev/null +++ b/AdvancedExample/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/AdvancedExample/gradlew.bat b/AdvancedExample/gradlew.bat new file mode 100644 index 00000000..8a0b282a --- /dev/null +++ b/AdvancedExample/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/AdvancedExample/settings.gradle b/AdvancedExample/settings.gradle new file mode 100644 index 00000000..e7b4def4 --- /dev/null +++ b/AdvancedExample/settings.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/BasicExample/app/libs/README b/BasicExample/app/libs/README old mode 100755 new mode 100644 diff --git a/BasicExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/MyActivity.java b/BasicExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/MyActivity.java index 6b95030e..d1a47452 100644 --- a/BasicExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/MyActivity.java +++ b/BasicExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/MyActivity.java @@ -64,6 +64,7 @@ private void orientVideoDescriptionFragment(int orientation) { } } + /** * The main fragment for displaying video content. */ @@ -112,6 +113,7 @@ public void onResume() { } } + /** * The fragment for displaying any video title or other non-video content. */ diff --git a/BasicExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoPlayerWithAdPlayback.java b/BasicExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoPlayerWithAdPlayback.java index 0574c847..3ce856e5 100644 --- a/BasicExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoPlayerWithAdPlayback.java +++ b/BasicExample/app/src/main/java/com/google/ads/interactivemedia/v3/samples/videoplayerapp/VideoPlayerWithAdPlayback.java @@ -225,7 +225,7 @@ public void restorePosition() { * the media controller. */ public void pauseContentForAdPlayback() { - mSavedContentVideoPosition = mVideoPlayer.getCurrentPosition(); + savePosition(); mVideoPlayer.stopPlayback(); } @@ -241,7 +241,7 @@ public void resumeContentAfterAdPlayback() { mIsAdDisplayed = false; mVideoPlayer.setVideoPath(mContentVideoUrl); mVideoPlayer.enablePlaybackControls(); - mVideoPlayer.seekTo(mSavedContentVideoPosition); + restorePosition(); mVideoPlayer.play(); } diff --git a/BasicExample/build.gradle b/BasicExample/build.gradle index 64a2348e..9b8abe4f 100644 --- a/BasicExample/build.gradle +++ b/BasicExample/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:0.+' + classpath 'com.android.tools.build:gradle:0.12.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/BasicExample/gradle/wrapper/gradle-wrapper.properties b/BasicExample/gradle/wrapper/gradle-wrapper.properties index b192b8d7..22d56bb8 100644 --- a/BasicExample/gradle/wrapper/gradle-wrapper.properties +++ b/BasicExample/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-all.zip diff --git a/BasicExample/gradlew b/BasicExample/gradlew old mode 100755 new mode 100644 diff --git a/LICENSE b/LICENSE old mode 100755 new mode 100644 diff --git a/README.md b/README.md index 96487dde..dcc728b1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ Google Ads Android IMA SDK This project hosts samples for the [Android IMA SDK](https://developers.google.com/interactive-media-ads/docs/sdks/android/v3/). ### Requirements - * Eclipse or Android Studio + * Android Studio + * IMA Android SDK .jar (see app/libs/README) ### Installation Instructions Installation instructions can be found in our [online documentation](https://developers.google.com/interactive-media-ads/docs/sdks/android/v3/quickstart). @@ -19,6 +20,6 @@ For more information, see the documentation at https://developers.google.com/int For API and client library updates and news, please follow our [Google+ Ads Developers page](https://plus.google.com/+GoogleAdsDevelopers/posts) and our [Google Ads Developers blog](http://googleadsdeveloper.blogspot.com/) -Copyright 2014 Google Inc. All Rights Reserved. +Copyright 2013 Google Inc. All Rights Reserved. You may study, modify, and use this example for any purpose. Note that this example is provided "as is", WITHOUT WARRANTY of any kind either expressed or implied. diff --git a/SampleVideoPlayer/app/libs/README b/SampleVideoPlayer/app/libs/README old mode 100755 new mode 100644 diff --git a/SampleVideoPlayer/build.gradle b/SampleVideoPlayer/build.gradle index 64a2348e..9b8abe4f 100644 --- a/SampleVideoPlayer/build.gradle +++ b/SampleVideoPlayer/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:0.+' + classpath 'com.android.tools.build:gradle:0.12.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/SampleVideoPlayer/gradle/wrapper/gradle-wrapper.properties b/SampleVideoPlayer/gradle/wrapper/gradle-wrapper.properties index ec4e4deb..71e12034 100644 --- a/SampleVideoPlayer/gradle/wrapper/gradle-wrapper.properties +++ b/SampleVideoPlayer/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-all.zip diff --git a/SampleVideoPlayer/gradlew b/SampleVideoPlayer/gradlew old mode 100755 new mode 100644