Support for video advertising

Components provided in the video support SDK

VideoAdView: This is the Custom View for video playback and sending tracking events. This can be allocated directly in the layout file.

VideoAdActivity: Activities displayed on the full screen. As with VideoAdView, video playback and tracking event transmission is performed, but the number of video playback control functions are increased.

Registration of VideoAdActivity

Use the SDK VideoAdActivity to support full-screen display with video SDK. Register this with AndroidManifest.xml.

<activity android:name="jp.fout.rfp.android.sdk.video.VideoAdActivity" />

Video advertising judgment

In case of video advertising, RFPInstreamInfoModel#isVideo() returns true. You can use this to judge whether there is any video advertising or not.

private boolean isAd(int position) {
    return getItem(position) instanceof RFPInstreamInfoModel;
}

private boolean isVideoAd(int position) {
    if (!isAd(position)) {
        return false;
    }
    RFPInstreamInfoModel item = (RFPInstreamInfoModel) getItem(position);
    return item.isVideo();
}

Processes video advertising information in VideoAdView

Detailed information on video advertising is stored in RFPInstreamInfoModel, and based on this, it is necessary to process in VideoAdView to assemble video advertisements. In the actual implementation, the RFPInstreamInfoModel instance is transferred to VideoAdView#processAd().

static class AdViewHolder {
    TextView advertiserName;
    TextView adText;
    ImageView adImage;
    TextView adSponsoredLabel;
    VideoAdView adVideo;

    AdViewHolder(View convertView) {
        advertiserName = (TextView) convertView.findViewById(R.id.custom_instream_advertiser_name);
        adText = (TextView) convertView.findViewById(R.id.custom_instream_ad_text);
        adImage = (ImageView) convertView.findViewById(R.id.custom_instream_ad_image);
        adSponsoredLabel = (TextView) convertView.findViewById(R.id.custom_instream_sponsor_name);
        adVideo = (VideoAdView) convertView.findViewById(R.id.custom_instream_video_view);
    }

    void setData(RFPInstreamInfoModel adData) {
        advertiserName.setText(adData.title());
        adText.setText(adData.content());

        String displayedAdvertiser = adData.displayedAdvertiser();
        if (null != displayedAdvertiser && 0 < displayedAdvertiser.length()) {
            adSponsoredLabel.setText(displayedAdvertiser);
        }

        adVideo.processAd(adData);
    }
}

Change the text of the button located in the video advertising

The text for the button located in the video advertising can be set from the advertising management screen. This set value can be obtained from RFPInstreamInfoModel#cta_text().

static class AdViewHolder {
    // ... ...
    Button adButton;

    AdViewHolder(View convertView) {
        // ... ...
        adButton = (Button) convertView.findViewById(R.id.custom_instream_action_button);
    }

    void setData(RFPInstreamInfoModel adData) {
        // ... ...
        String adButtonText = adData.cta_text();
        if (adButtonText != null && adButtonText.length() > 0) {
            adButton.setText(adButtonText);
        }

        adVideo.processAd(adData);
    }
}

Video playback

This calls VideoAdView#processAd(), and playback starts automatically once video playback is possible.

By setting VideoAdView#setAutoStart(false), it is possible to control automatic playback. In this case, it is necessary to call VideoAdView#play() from the app and start playback. Furthermore, by calling VideoAdView#pause(), it is possible to stop at any point.

Transition to full-screen mode

Tap the video area to move to full-screen display.

This behavior is the default action, and when full-screen mode ends, additional implementation is required if you want to synchronize the video playback position when full-screen mode ends.

Full-screen mode is an Activity, so to carry on the playback position and tracking event transmission mode, transfer the results with Activity#startActivityForResult() and Activity#onActivityResult().

As VideoAdView calls OnFullscreenRequestListener#onRequestFullscreen() when moving to full-screen mode, this is implemented. As the target ‘VideoAdView” and the intent to take over the information are passed as arguments, Activity#startActivityForResult() is called based on this. Use RFP.getVideoAdFullscreenRequestCode() as the request code for the Activity.

By using VideoAdView#restore(Intent), it is possible to carry over the playback position and the tracking event transmission state.

It is necessary to know VideoAdView for which the Activity is VideoAdView#restore(Intent), but by implementing VideoAdView.OnFullscreenRequestListener, which is the full screen callback for VideoAdView, this can be notified as an Activity.

In the following example, greenrobot/EventBus is used to notify and save VideoAdView as an Activity.

class VideoAdViewHolder extends RecyclerView.ViewHolder
        implements VideoAdView.OnFullscreenRequestListener {
    RFPInstreamAdPlacer adPlacer;
    VideoAdView adVideo;

    VideoAdViewHolder(View itemView, RFPInstreamAdPlacer placer) {
        super(itemView);
        adPlacer = placer;

        // ... ...

        adVideo = (VideoAdView) itemView.findViewById(R.id.custom_instream_ad_image);
        adVideo.setOnFullscreenRequestListener(this);
    }

    @Override
    public void onRequestFullscreen(VideoAdView view, Intent intent) {
        EventBus.getDefault().post(new RequestFullscreenEvent(view, intent));
    }
}
VideoAdView mSourceVideoAdView = null;

@Subscribe(threadMode = ThreadMode.MAIN)
public void onRequestFullscreen(RequestFullscreenEvent event) {
    mSourceVideoAdView = event.view;
    startActivityForResult(event.intent, RFP.getVideoAdFullscreenRequestCode());
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == RFP.getVideoAdFullscreenRequestCode()
            && resultCode == Activity.RESULT_OK
            && mSourceVideoAdView != null) {
        mSourceVideoAdView.restore(data);
    }
}

The RFP#getVideoAdFullscreenRequestCode() default value is 18416, and by using RFP#setVideoAdFullscreenRequestCode(int), this can be changed to any value.

RFP.setVideoAdFullscreenRequestCode(1000);

When controlling automatic playback using VideoAdView#setAutoStart(), it is necessary to call VideoAdView#play() on recovery.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == RFP.getVideoAdFullscreenRequestCode()
            && resultCode == Activity.RESULT_OK
            && mSourceVideoAdView != null) {
        mSourceVideoAdView.restore(data);
        mSourceVideoAdView.play();
    }
}

Playback control when transitioning to modes

When transitioning to full-screen mode, and moving to the landing page with the action button, this must be stopped in order to retrieve the tracking event correctly.

The transition to full-screen mode and the action button within full-screen mode are all handled correctly within SDK, but for the action button within the feed for control on the app side, it is necessary to describe the video stop processing. Describe VideoAdView#pause() as either Activity#onStop() or Activity#onPause() when utilizing onClick`.

VideoAdView adVideo = (VideoAdView) itemView.findViewById(R.id.custom_instream_ad_image);
Button adButton = (Button) itemView.findViewById(R.id.custom_instream_ad_action_button);
adButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        adVideo.pause();
        adPlacer.sendClickEvent(adData);
    }
});

Customizing video area tap behavior

By default, tap video area to move to full-screen display, you can customize this behavior via VideoAdView#setOnVideoAreaClickListener(OnClickLisner).

An example for customizing video area tap behavior below:

RFPInstreamAdPlacer adPlacer;

VideoAdViewHolder(View itemView, RFPInstreamAdPlacer placer) {
    super(itemView);

    adPlacer = placer;
}

public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (holder.getItemViewType() == ITEM_VIEW_TYPE_AD_VIDEO) {
        final VideoAdViewHolder h = (VideoAdViewHolder) holder;
        final RFPInstreamInfoModel model = (RFPInstreamInfoModel) mModels.get(position);
        h.adVideoView.setOnVideoAreaClickListener(new OnClickListener() {
            public void onClick(View v) {
                h.adVideoView.pause();
                adPlacer.sendClickEvent(model);
            }
        }
    } else {
        // ... ...
    }
}

Support for video advertisement load errors

When an error occurs on loading video advertisements, you can describe and control the error processing.

When inside a feed

Implement VideoAdView#OnErrorListener within the feed, and set the listener with VideoAdView#setOnErrorListener().

static class AdViewHolder implements VideoAdView.OnErrorListener {
    VideoAdView adVideo;

    VideoAdViewHolder(View itemView, RFPInstreamAdPlacer placer) {
        super(itemView);

        // ... ...

        adVideo = (VideoAdView) itemView.findViewById(R.id.custom_instream_ad_image);
        adVideo.setOnErrorListener(this);
    }
    @Override
    public void onError(VideoAdView view, String message, @Nullable Throwable t) {
        // view: VideoAdView in which error occurred
        // message: Error content
        // t: relevant exception where an exception has occurred
        Log.d(TAG, message, t);
    }
}

In the case of full screen

Where an error occurs in full screen, the activity is ended and RESULT_CANCELED is found in the onActivityResult() resultCode. It is possible to describe error processing by judging based on this. In such a case, the error content can be found in Intent.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == RFP.getVideoAdFullscreenRequestCode()) {
        if (resultCode == Activity.RESULT_OK) {
            // Normal processing
        } else if (resultCode == Activity.RESULT_CANCELED) {
            // Processing on errors
            String message = data.getStringExtra("error_message");
            Throwable t = (Throwable) data.getSerializableExtra("error");
            Log.d(TAG, message, t);
        }
    }
}

Cache settings

RFP can store a certain amount of video advertisements within the internal storage cache area.

For the cache capacity, use the setting values recommended by RFP. This value can be changed from the app side.

int size = RFP.getVideoCacheSize(); //Returns the current setting value
RFP.setVideoCacheSize(50); // Uses 50 MB as the cache area
RFP.setVideoCacheSize(0);  // Disables the cache

Resuming video when it is reattach to the view

SDK does not save video’s state when it’s detached from its parent view. This behavior is the default action and additional implementation is needed if you want to synchronize the video playback position when it’s reattach to the parent view.

When VideoAdView is detached from its parent view, by implementing VideoAdView#OnDetachedListener will get VideoAdView’s Bundle information for synchronize.

When VideoAdView is reattach to the parent view, please pass the stored Bundle to VideoAdView#processAd(RFPInstreamInfoModel adModel, @Nullable Bundle savedState) for taking over the playback state.

// store ad's information for resume
private SparseArray<Bundle> mResumeVideosArray = new SparseArray<>();

public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (holder.getItemViewType() == ITEM_VIEW_TYPE_AD_VIDEO) {
        final VideoAdViewHolder h = (VideoAdViewHolder) holder;
        final RFPInstreamInfoModel model = (RFPInstreamInfoModel) mModels.get(position);

        // get resume ad's information if exist
        Bundle state = mResumeVideosArray.get(position);
        // remove ad's old information if exist
        mResumeVideosArray.remove(position);
        // reset ad's information when it's detached from window
        h.adVideoView.setOnDetachedListener(bundle -> mResumeVideosArray.put(position, bundle));
        h.setData(adInfo, null, state);
    } else {
        // ... ...
    }
}

static class AdViewHolder {
    VideoAdView adVideo;
    // ... ...

    AdViewHolder(View convertView) {
        adVideo = (VideoAdView) itemView.findViewById(R.id.custom_instream_ad_image);
        // ... ...
    }

    void setData(RFPInstreamInfoModel adData, Bundle savedState) {
        // ... ...
        // restart ad from the position when being detached
        adVideo.processAd(adData, savedState);
    }