package com.kaltura.playersdk;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.BounceInterpolator;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import com.kaltura.playersdk.actionHandlers.ShareManager;
import com.kaltura.playersdk.casting.KCastProviderV3Impl;
import com.kaltura.playersdk.events.KPErrorEventListener;
import com.kaltura.playersdk.events.KPEventListener;
import com.kaltura.playersdk.events.KPFullScreenToggledEventListener;
import com.kaltura.playersdk.events.KPPlayheadUpdateEventListener;
import com.kaltura.playersdk.events.KPStateChangedEventListener;
import com.kaltura.playersdk.events.KPlayerState;
import com.kaltura.playersdk.helpers.CacheManager;
import com.kaltura.playersdk.helpers.KStringUtilities;
import com.kaltura.playersdk.interfaces.KCastProvider;
import com.kaltura.playersdk.interfaces.KMediaControl;
import com.kaltura.playersdk.interfaces.KPrefetchListener;
import com.kaltura.playersdk.players.KMediaFormat;
import com.kaltura.playersdk.players.KPlayer;
import com.kaltura.playersdk.players.KPlayerController;
import com.kaltura.playersdk.players.KPlayerListener;
import com.kaltura.playersdk.tracks.KTrackActions;
import com.kaltura.playersdk.tracks.TrackType;
import com.kaltura.playersdk.types.KPError;
import com.kaltura.playersdk.types.NativeActionType;
import com.kaltura.playersdk.utils.Utilities;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.kaltura.playersdk.utils.LogUtils.LOGD;
import static com.kaltura.playersdk.utils.LogUtils.LOGE;
/**
* Created by michalradwantzor on 9/24/13.
*/
public class PlayerViewController extends RelativeLayout implements KControlsView.KControlsViewClient, KPlayerListener {
public static String TAG = "PlayerViewController";
private KPlayerController playerController;
public KControlsView mWebView = null;
private double mCurSec;
private Activity mActivity;
// private OnShareListener mShareListener;
private JSONObject nativeActionParams;
private KPPlayerConfig mConfig;
private String mIframeUrl = null;
private boolean mWvMinimized = false;
private int newWidth, newHeight;
private boolean mIsJsCallReadyRegistration = false;
private Set<ReadyEventListener> mCallBackReadyRegistrations;
private final HashMap<String, ArrayList<HashMap<String, EventListener>>> mPlayerEventsHash = new HashMap<>();
private HashMap<String, EvaluateListener> mPlayerEvaluatedHash;
private Set<KPEventListener> eventListeners;
private KPErrorEventListener mOnKPErrorEventListener;
private KPFullScreenToggledEventListener mOnKPFullScreenToggledEventListener;
private KPStateChangedEventListener mOnKPStateChangedEventListener;
private KPPlayheadUpdateEventListener mOnKPPlayheadUpdateEventListener;
private SourceURLProvider mCustomSourceURLProvider;
private boolean isFullScreen = false;
private boolean isMediaChanged = false;
private boolean shouldReplay = false;
private boolean prepareWithConfigurationMode = false;
private KCastProvider mCastProvider;
public static void prefetchPlayerResources(KPPlayerConfig config, final List<Uri> uriItemsList, final KPrefetchListener prefetchListener, Activity activity) {
LOGD(TAG, "Start prefetchPlayerResources");
final PlayerViewController player = new PlayerViewController(activity);
player.loadPlayerIntoActivity(activity);
config.addConfig("EmbedPlayer.PreloadNativeComponent", "true");
player.initWithConfiguration(config);
final CacheManager cacheManager = new CacheManager(activity.getApplicationContext());
cacheManager.setBaseURL(Utilities.stripLastUriPathSegment(config.getServerURL()));
cacheManager.setCacheSize(config.getCacheSize());
if (uriItemsList != null && !uriItemsList.isEmpty()) {
Thread thread = new Thread(new Runnable() {
public void run() {
try {
for (Uri uriItem : uriItemsList)
cacheManager.cacheResponse(uriItem);
} catch (IOException e) {
e.printStackTrace();
}
}
});
thread.start();
}
player.registerReadyEvent(new ReadyEventListener() {
@Override
public void handler() {
LOGD(TAG, "Player ready after prefetch - will now destroy player");
player.removePlayer();
if (prefetchListener != null) {
prefetchListener.onPrefetchFinished();
}
}
});
}
public KCastProvider setCastProvider(KCastProvider castProvider) {
boolean isFirstSetup = true;
if (mCastProvider != null) { //From 2.50 - //if (mCastProvider != null || (castProvider != null && castProvider.getNumOfConnectedSenders() > 1)) {
isFirstSetup = false;
}
mCastProvider = castProvider;
if (mCastProvider == null) {
return null;
}
mCastProvider.init(mActivity);
boolean isReconnect = mCastProvider.isReconnected() || mCastProvider.getSelectedCastDevice() != null;
boolean isCasting = mCastProvider.isCasting();
if (isCasting || mCastProvider.getSelectedCastDevice() != null) {
mCastProvider.startReceiver(mActivity);
}
playerController.setCastProvider(mCastProvider);
if (isReconnect) {
mWebView.triggerEvent("chromecastDeviceDisConnected", null);
}
mWebView.triggerEvent("chromecastDeviceConnected", "" + getCurrentPlaybackTime());
if(isReconnect) { // From 2.50 if(isReconnect && (isCasting || !isFirstSetup)) { // && !isFirstSetup) || mCastProvider.getSessionEntryID() != null) {
asyncEvaluate("{mediaProxy.entry.id}", "EntryId", new PlayerViewController.EvaluateListener() {
@Override
public void handler(final String idEvaluateResponse) {
if (idEvaluateResponse != null && !"null".equals(idEvaluateResponse)) {
pause();
if (mCastProvider != null && mCastProvider.isCasting()) {
LOGD(TAG, "----- Before Sending new AD Tag on CC --------");
String newAdTag = getConfig().getConfigValueString("doubleClick.adTagUrl");
if (newAdTag != null) {
LOGD(TAG, "----- Sending new AD Tag to CC --------");
((KCastProviderV3Impl)mCastProvider).sendMessage("{\"type\":\"setKDPAttribute\",\"plugin\":\"doubleClick\",\"property\":\"adTagUrl\",\"value\":\"" + newAdTag + "\"}");
}
}
if (getConfig().getConfigValueString("proxyData") == null || "".equals(getConfig().getConfigValueString("proxyData"))) {
castChangeMedia(idEvaluateResponse);
} else {
try {
JSONObject changeMediaJSON = new JSONObject();
JSONObject proxyData = new JSONObject(getConfig().getConfigValueString("proxyData"));
changeMediaJSON.put("entryId", idEvaluateResponse);
changeMediaJSON.put("proxyData", proxyData);
castChangeMedia(changeMediaJSON);
} catch (JSONException e) {
LOGE(TAG, "Error could not create change media proxy dat object");
}
}
}
}
});
}
return mCastProvider;
}
public KCastProvider getCastProvider() {
return mCastProvider;
}
@Override
public void setOnTouchListener(OnTouchListener l) {
if (mWebView != null) {
mWebView.setOnTouchListener(l);
}
}
// trigger timeupdate events
public interface EventListener {
void handler(String eventName, String params);
}
public interface ReadyEventListener {
void handler();
}
public interface EvaluateListener {
void handler(String evaluateResponse);
}
public interface SourceURLProvider {
String getURL(String entryId, String currentURL);
}
public PlayerViewController(Context context) {
super(context);
}
public PlayerViewController(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PlayerViewController(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public KMediaControl getMediaControl() {
return playerController;
}
public KTrackActions getTrackManager(){
return playerController.getTracksManager();
}
public void initWithConfiguration(KPPlayerConfig configuration) {
mConfig = configuration;
if (mConfig != null) {
setComponents(mConfig.getVideoURL());
}
}
public void setPrepareWithConfigurationMode(boolean prepareWithConfigurationMode) {
this.prepareWithConfigurationMode = prepareWithConfigurationMode;
}
public void loadPlayerIntoActivity(Activity activity) {
registerReadyEvent(new ReadyEventListener() {
@Override
public void handler() {
if (eventListeners != null) {
for (KPEventListener listener: eventListeners) {
listener.onKPlayerStateChanged(PlayerViewController.this, KPlayerState.PRE_LOADED);
}
}
if (mOnKPStateChangedEventListener != null) {
mOnKPStateChangedEventListener.onKPlayerStateChanged(PlayerViewController.this, KPlayerState.PRE_LOADED);
}
}
});
mActivity = activity;
}
@Deprecated
public void addEventListener(KPEventListener listener) {
if (listener != null) {
if (eventListeners == null) {
eventListeners = new HashSet<>();
}
eventListeners.add(listener);
}
}
public void setOnKPErrorEventListener(KPErrorEventListener kpErrorEventListener) {
mOnKPErrorEventListener = kpErrorEventListener;
}
public void setOnKPFullScreenToggledEventListener(KPFullScreenToggledEventListener kpFullScreenToggledEventListener) {
mOnKPFullScreenToggledEventListener = kpFullScreenToggledEventListener;
}
public void setOnKPStateChangedEventListener(KPStateChangedEventListener kpStateChangedEventListener) {
mOnKPStateChangedEventListener = kpStateChangedEventListener;
}
public void setOnKPPlayheadUpdateEventListener(KPPlayheadUpdateEventListener kpPlayheadUpdateEventListener) {
mOnKPPlayheadUpdateEventListener = kpPlayheadUpdateEventListener;
}
public KPPlayerConfig getConfig() {
return mConfig;
}
public void changeMedia(String entryId) {
if (entryId != null && entryId.length() > 0) {
JSONObject entryJson = new JSONObject();
try {
isMediaChanged = true;
entryJson.put("entryId", entryId);
String jsonString = entryJson.toString();
playerController.changeMedia();
sendNotification("changeMedia",jsonString);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
public void changeMedia(JSONObject proxyData) {
if (proxyData == null) {
return;
}
isMediaChanged = true;
playerController.changeMedia();
sendNotification("changeMedia", proxyData.toString());
}
public void castChangeMedia(String entryId) {
if (entryId != null && entryId.length() > 0) {
JSONObject entryJson = new JSONObject();
try {
isMediaChanged = true;
entryJson.put("entryId", entryId);
String jsonString = entryJson.toString();
playerController.castChangeMedia();
sendNotification("changeMedia",jsonString);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
public void castChangeMedia(JSONObject proxyData) {
if (proxyData == null) {
return;
}
isMediaChanged = true;
playerController.castChangeMedia();
sendNotification("changeMedia", proxyData.toString());
}
public void changeConfiguration(KPPlayerConfig config) {
if (config != null) {
resetPlayer();
mConfig = config;
mWebView.setVisibility(INVISIBLE);
mWebView.clearCache(true);
mWebView.clearHistory();
mWebView.loadUrl("about:blank");
mWebView.loadUrl(config.getVideoURL() + buildSupportedMediaFormats());
mIsJsCallReadyRegistration = false;
registerReadyEvent(new ReadyEventListener() {
@Override
public void handler() {
mWebView.setVisibility(VISIBLE);
if (mPlayerEventsHash != null) {
for (String event : mPlayerEventsHash.keySet()) {
mWebView.addEventListener(event);
}
}
}
});
}
}
@Deprecated
public void removeEventListener(KPEventListener listener) {
if (listener != null && eventListeners != null && eventListeners.contains(listener)) {
eventListeners.remove(listener);
}
}
public void setCustomSourceURLProvider(SourceURLProvider provider) {
mCustomSourceURLProvider = provider;
}
private String getOverrideURL(String entryId, String currentURL) {
if (mCustomSourceURLProvider != null) {
String overrideURL = mCustomSourceURLProvider.getURL(entryId, currentURL);
if (overrideURL != null) {
return overrideURL;
}
}
return currentURL;
}
public void freeze(){
if(playerController != null) {
playerController.pause();
}
}
public void saveState() {
saveState(false);
}
public void saveState(boolean isOnBackground) {
playerController.savePlayerState();
}
public void resumeState() {
playerController.recoverPlayerState();
}
/**
* Release player's instance and save its last position for resuming later on.
* This method should be called when the main activity is paused.
*/
public void releaseAndSavePosition() {
releaseAndSavePosition(false);
}
public void releaseAndSavePosition(boolean shouldResumeState) {
if (playerController != null) {
playerController.removePlayer(shouldResumeState);
}
}
public void releaseAndSavePosition(boolean shouldResumeState, boolean mShouldPauseChromecastInBg) {
if (playerController != null) {
playerController.removePlayer(shouldResumeState, mShouldPauseChromecastInBg);
}
}
public void resetPlayer() {
if (playerController != null) {
playerController.reset();
}
}
/**
* Recover from "releaseAndSavePosition", reload the player from previous position.
* This method should be called when the main activity is resumed.
*/
public void resumePlayer() {
if (playerController != null) {
playerController.recoverPlayer();
}
}
public void removePlayer() {
if (playerController != null) {
playerController.destroy();
}
if (mWebView != null) {
try {
mWebView.loadUrl("about:blank");
} catch(NullPointerException e){
LOGE(TAG, "WebView NullPointerException caught " + e.getMessage());
}
removeView(mWebView);
mWebView.destroy();
}
}
public void setActivity( Activity activity ) {
mActivity = activity;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
// public void setOnShareListener(OnShareListener listener) {
// mShareListener = listener;
// }
private void setVolumeLevel(double percent) {//Itay
AudioManager mgr = (AudioManager) mActivity.getSystemService(Context.AUDIO_SERVICE);
if (percent > 0.01) {
while (percent < 1.0) {
percent *= 10;
}
}
mgr.setStreamVolume(AudioManager.STREAM_MUSIC, (int) percent, 0);
}
@SuppressLint("NewApi") private Point getRealScreenSize(){
Display display = mActivity.getWindowManager().getDefaultDisplay();
int realWidth = 0;
int realHeight = 0;
if (Build.VERSION.SDK_INT >= 17){
//new pleasant way to get real metrics
DisplayMetrics realMetrics = new DisplayMetrics();
display.getRealMetrics(realMetrics);
realWidth = realMetrics.widthPixels;
realHeight = realMetrics.heightPixels;
} else {
try {
Method mGetRawH = Display.class.getMethod("getRawHeight");
Method mGetRawW = Display.class.getMethod("getRawWidth");
realWidth = (Integer) mGetRawW.invoke(display);
realHeight = (Integer) mGetRawH.invoke(display);
} catch (Exception e) {
realWidth = display.getWidth();
realHeight = display.getHeight();
LOGE(TAG, "Display Info - Couldn't use reflection to get the real display metrics.");
}
}
return new Point(realWidth,realHeight);
}
/**
* Sets the player's dimensions. Should be called for any player redraw
* (for example, in screen rotation, if supported by the main activity)
* @param width player's width
* @param height player's height
* @param xPadding player's X position
* @param yPadding player's Y position
* @deprecated Use {@link #setLayoutParams(ViewGroup.LayoutParams)} instead.
*/
@Deprecated
public void setPlayerViewDimensions(int width, int height, int xPadding, int yPadding) {
setPadding(xPadding, yPadding, 0, 0);
newWidth = width + xPadding;
newHeight = height + yPadding;
ViewGroup.LayoutParams lp = getLayoutParams();
if ( lp == null ) {
lp = new ViewGroup.LayoutParams( newWidth, newHeight );
} else {
lp.width = newWidth;
lp.height = newHeight;
}
this.setLayoutParams(lp);
for ( int i = 0; i < this.getChildCount(); i++ ) {
View v = getChildAt(i);
if( v == playerController.getPlayer() )
{
continue;
}
ViewGroup.LayoutParams vlp = v.getLayoutParams();
vlp.width = newWidth;
if ( (!mWvMinimized || !v.equals( mWebView)) ) {//
vlp.height = newHeight;
}
updateViewLayout(v, vlp);
}
if(mWebView != null) {
// mWebView.loadUrl("javascript:android.onData(NativeBridge.videoPlayer.getControlBarHeight())");
mWebView.fetchControlsBarHeight(new KControlsView.ControlsBarHeightFetcher() {
@Override
public void fetchHeight(int controlBarHeight) {
if ( playerController.getPlayer() != null && playerController.getPlayer() instanceof FrameLayout && ((FrameLayout)playerController.getPlayer()).getParent() == PlayerViewController.this ) {
LayoutParams wvLp = (LayoutParams) ((View) playerController.getPlayer()).getLayoutParams();
if (getPaddingLeft() == 0 && getPaddingTop() == 0) {
wvLp.addRule(CENTER_IN_PARENT);
} else {
wvLp.addRule(CENTER_IN_PARENT, 0);
}
float scale = mActivity.getResources().getDisplayMetrics().density;
controlBarHeight = (int) (controlBarHeight * scale + 0.5f);
wvLp.height = newHeight - controlBarHeight;
wvLp.width = newWidth;
wvLp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
final LayoutParams lp = wvLp;
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
updateViewLayout((View) playerController.getPlayer(), lp);
invalidate();
}
});
}
}
});
}
invalidate();
}
/**
* Sets the player's dimensions. Should be called for any player redraw
* (for example, in screen rotation, if supported by the main activity)
* Player's X and Y position will be 0
* @param width player's width
* @param height player's height
* @deprecated Use {@link #setLayoutParams(ViewGroup.LayoutParams)} instead.
*/
@Deprecated
public void setPlayerViewDimensions(int width, int height) {
//noinspection deprecation
setPlayerViewDimensions(width, height, 0, 0);
}
private void setChromecastVisiblity() {
// mWebView.setKDPAttribute("chromecast", "visible", ChromecastHandler.routeInfos.size() > 0 ? "true" : "false");
}
/*
* Build player URL and load it to player view
* @param requestDataSource - RequestDataSource object
*/
/**
* Build player URL and load it to player view
* param iFrameUrl- String url
*/
public void setComponents(String iframeUrl) {
if(mWebView == null) {
mWebView = new KControlsView(this.mActivity);
mWebView.setId(R.id.webView_1);
mWebView.setKControlsViewClient(this);
mCurSec = 0;
LayoutParams wvLp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
mWebView.setLayoutParams(wvLp);
setBackgroundColor(Color.BLACK);
playerController = new KPlayerController(this);
if (prepareWithConfigurationMode){
LOGD(TAG,"setComponents prepareWithConfigurationMode = " + prepareWithConfigurationMode);
playerController.setPrepareWithConfigurationMode(true);
}
this.addView(mWebView);
}
iframeUrl += buildSupportedMediaFormats();
if( mIframeUrl == null || !mIframeUrl.equals(iframeUrl) ) {
mIframeUrl = iframeUrl;
Uri uri = Uri.parse(iframeUrl);
if (mConfig.getCacheSize() > 0) {
CacheManager cacheManager = new CacheManager(mActivity.getApplicationContext());
cacheManager.setBaseURL(Utilities.stripLastUriPathSegment(mConfig.getServerURL()));
cacheManager.setCacheSize(mConfig.getCacheSize());
cacheManager.setIncludePatterns(mConfig.getCacheConfig().includePatterns);
mWebView.setCacheManager(cacheManager);
}
mWebView.loadUrl(iframeUrl);
}
}
/**
* create PlayerView / CastPlayer instance according to cast status
*/
private void replacePlayerViewChild( View newChild, View oldChild ) {
if ( oldChild.getParent().equals( this ) ) {
this.removeView( oldChild );
}
if ( this.getChildCount() > 1 ) {
//last child is the KMediaControl webview
this.addView( newChild , this.getChildCount() -1, oldChild.getLayoutParams() );
}
}
/**
* slides with animation according the given values
*
* @param x
* x offset to slide
* @param duration
* animation time in milliseconds
*/
public void slideView(int x, int duration) {
this.animate().xBy(x).setDuration(duration)
.setInterpolator(new BounceInterpolator());
}
// /////////////////////////////////////////////////////////////////////////////////////////////
// VideoPlayerInterface methods
// /////////////////////////////////////////////////////////////////////////////////////////////
// public boolean isPlaying() {
// return (playerController.getPlayer() != null && playerController.getPlayer().isPlaying());
// }
/**
*
* @return duration in seconds
*/
public double getDurationSec() {
double duration = 0;
if (playerController != null) {
duration = playerController.getDuration() / 1000;
}
return duration;
}
public String getVideoUrl() {
String url = null;
if (playerController != null)
url = playerController.getSrc();
return url;
}
public double getCurrentPlaybackTime() {
if (playerController != null) {
return playerController.getCurrentPlaybackTime();
}
return 0.0;
}
// /////////////////////////////////////////////////////////////////////////////////////////////
// Kaltura Player external API
// /////////////////////////////////////////////////////////////////////////////////////////////
// public void sendNotification(String noteName, JSONObject noteBody) {
// notifyKPlayer("sendNotification", new String[]{noteName, noteBody.toString()});
// }
/////////////////////////////////////////////////////////////////////////////////////////////////
/**
* call js function on NativeBridge.videoPlayer
*
* @param action
* function name
* @param eventValues
* function arguments
*/
private void notifyKPlayer(final String action, final Object[] eventValues) {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
String values = "";
if (eventValues != null) {
for (int i = 0; i < eventValues.length; i++) {
if (eventValues[i] instanceof String) {
values += "'" + eventValues[i] + "'";
} else {
values += eventValues[i].toString();
}
if (i < eventValues.length - 1) {
values += ", ";
}
}
// values = TextUtils.join("', '", eventValues);
}
if (mWebView != null) {
LOGD(TAG, "NotifyKplayer: " + values);
mWebView.loadUrl("javascript:NativeBridge.videoPlayer."
+ action + "(" + values + ");");
}
}
});
}
@Override
public void handleHtml5LibCall(String functionName, int callbackId, String args) {
LOGD(TAG + " handleHtml5LibCall", functionName + " " + args);
Method bridgeMethod = KStringUtilities.isMethodImplemented(this, functionName);
Object object = this;
if (bridgeMethod == null) {
KPlayer player = playerController.getPlayer();
bridgeMethod = KStringUtilities.isMethodImplemented(player, functionName);
object = player;
}
if (bridgeMethod != null) {
try {
if (args == null) {
Class<?>[] params = bridgeMethod.getParameterTypes(); // protect case for params mismatch
if (params.length != 1){
bridgeMethod.invoke(object);
}
else {
LOGE(TAG, "Error, handleHtml5LibCall Parameters mismatch for method: " + functionName + " number of params = " + params.length);
}
} else {
bridgeMethod.invoke(object, args);
}
} catch (Exception e) {
LOGE(TAG, "Error calling bridgeMethod " + bridgeMethod, e);
}
}
}
@Override
public void openURL(String url) {
final Intent intent = new Intent(Intent.ACTION_VIEW).setData(Uri.parse(url));
mActivity.startActivity(intent);
}
@Override
public void handleKControlsError(KPError error) {
sendOnKPlayerError(error.getErrorMsg());
}
//
@Override
public void eventWithValue(KPlayer player, String eventName, String eventValue) {
LOGD(TAG, "EventWithValue Name: " + eventName + " Value: " + eventValue);
KStringUtilities event = new KStringUtilities(eventName);
KPlayerState kState = KPlayerState.getStateForEventName(eventName);
if ((isMediaChanged && kState == KPlayerState.READY && getConfig().isAutoPlay())) {
isMediaChanged = false;
play();
}
if (kState == KPlayerState.SEEKED && shouldReplay) {
shouldReplay = false;
play();
}
if (eventListeners != null) {
for (KPEventListener listener : eventListeners) {
if (!KPlayerState.UNKNOWN.equals(kState)) {
if (kState == KPlayerState.READY && "CC".equals(eventValue)) {
listener.onKPlayerStateChanged(this, KPlayerState.CC_READY);
eventValue = null;
} else {
listener.onKPlayerStateChanged(this, kState);
}
} else if (event.isTimeUpdate()) {
listener.onKPlayerPlayheadUpdate(this, Float.parseFloat(eventValue));
} else if (event.isEnded()) {
listener.onKPlayerStateChanged(this, KPlayerState.ENDED);
}
}
}
if (mOnKPStateChangedEventListener != null) {
if (!KPlayerState.UNKNOWN.equals(kState)) {
if (kState == KPlayerState.READY && "CC".equals(eventValue)) {
mOnKPStateChangedEventListener.onKPlayerStateChanged(this, KPlayerState.CC_READY);
eventValue = null;
} else {
mOnKPStateChangedEventListener.onKPlayerStateChanged(this, kState);
}
}
}
if (mOnKPPlayheadUpdateEventListener != null) {
if (event.isTimeUpdate()) {
mOnKPPlayheadUpdateEventListener.onKPlayerPlayheadUpdate(this, (long) (Float.parseFloat(eventValue) * 1000));
}
}
if(KPlayerListener.ErrorKey.equals(eventName) && !getConfig().isWebDialogEnabled()) {
LOGE(TAG, "blocking Dialog for: " + eventValue);
if (eventValue.contains("Socket")) {
String isExternalAdPlayer = getConfig().getConfigValueString("EmbedPlayer.UseExternalAdPlayer");
if (player != null && isExternalAdPlayer != null && "true".equals(isExternalAdPlayer)) {
setPrepareWithConfigurationMode(false);
player.setPrepareWithConfigurationModeOff();
}
asyncEvaluate("{mediaProxy.entry.id}", "EntryId", new PlayerViewController.EvaluateListener() {
@Override
public void handler(final String idEvaluateResponse) {
if (idEvaluateResponse != null && !"null".equals(idEvaluateResponse)) {
if (getConfig().getConfigValueString("proxyData") == null || "".equals(getConfig().getConfigValueString("proxyData"))) {
changeMedia(idEvaluateResponse);
} else {
try {
JSONObject changeMediaJSON = new JSONObject();
JSONObject proxyData = new JSONObject(getConfig().getConfigValueString("proxyData"));
changeMediaJSON.put("entryId", idEvaluateResponse);
changeMediaJSON.put("proxyData", proxyData);
changeMedia(changeMediaJSON);
} catch (JSONException e) {
LOGE(TAG, "Error could not create change media proxy dat object");
}
}
}
}
});
}
sendOnKPlayerError(eventValue);
return;
}
this.mWebView.triggerEvent(eventName, eventValue);
}
@Override
public void eventWithJSON(KPlayer player, String eventName, String jsonValue) {
this.mWebView.triggerEventWithJSON(eventName, jsonValue);
}
private void play() {
playerController.play();
}
private void pause() {
playerController.pause();
}
public void registerReadyEvent(ReadyEventListener listener) {
if (mIsJsCallReadyRegistration) {
listener.handler();
} else {
if (mCallBackReadyRegistrations == null && listener != null) {
mCallBackReadyRegistrations = new HashSet<>();
}
mCallBackReadyRegistrations.add(listener);
}
}
public void addKPlayerEventListener(final String event, final String eventID, final EventListener listener) {
this.registerReadyEvent(new ReadyEventListener() {
@Override
public void handler() {
ArrayList<HashMap<String, EventListener>> listenerArr = (ArrayList)mPlayerEventsHash.get(event);
if (listenerArr == null) {
listenerArr = new ArrayList();
}
HashMap<String, EventListener> addedEvent = new HashMap();
addedEvent.put(eventID, listener);
listenerArr.add(addedEvent);
mPlayerEventsHash.put(event, listenerArr);
if (listenerArr.size() == 1 && !KStringUtilities.isToggleFullScreen(event)) {
mWebView.addEventListener(event);
}
}
});
}
public void removeKPlayerEventListener(String event,String eventID) {
if (mPlayerEventsHash == null) {
return;
}
ArrayList<HashMap<String, EventListener>> listenerArr = mPlayerEventsHash.get(event);
if (listenerArr == null || listenerArr.size() == 0) {
return;
}
ArrayList<HashMap<String, EventListener>> temp = new ArrayList<HashMap<String, EventListener>>(listenerArr);
for (HashMap<String, EventListener> hash: temp) {
if (hash.keySet().toArray()[hash.keySet().size() - 1].equals(eventID)) {
listenerArr.remove(hash);
}
}
if (listenerArr.size() == 0) {
listenerArr = null;
if (!KStringUtilities.isToggleFullScreen(event)) {
mWebView.removeEventListener(event);
}
}
}
@Override
public void asyncEvaluate(String expression, String expressionID, EvaluateListener evaluateListener) {
if (mPlayerEvaluatedHash == null) {
mPlayerEvaluatedHash = new HashMap<String, EvaluateListener>();
}
mPlayerEvaluatedHash.put(expressionID, evaluateListener);
//mWebView.triggerEvent("asyncEvaluate", expression);
mWebView.evaluate(expression, expressionID);
}
public void sendNotification(String notificationName,@Nullable String params) {
if (mWebView != null) {
if (notificationName == null) {
notificationName = "null";
}
mWebView.sendNotification(notificationName, params);
}
}
public void setKDPAttribute(final String pluginName, final String propertyName, final String value) {
registerReadyEvent(new ReadyEventListener() {
@Override
public void handler() {
mWebView.setKDPAttribute(pluginName, propertyName, value);
}
});
}
public void setStringKDPAttribute(final String pluginName, final String propertyName, final String value) {
registerReadyEvent(new ReadyEventListener() {
@Override
public void handler() {
mWebView.setStringKDPAttribute(pluginName, propertyName, value);
}
});
}
public void setKDPAttribute(final String pluginName, final String propertyName, final JSONObject value) {
registerReadyEvent(new ReadyEventListener() {
@Override
public void handler() {
mWebView.setKDPAttribute(pluginName, propertyName, value);
}
});
}
public void triggerEvent(String event, String value) {
mWebView.triggerEvent(event, value);
}
/// Bridge methods
private void setAttribute(String argsString) {
String[] args = KStringUtilities.fetchArgs(argsString);
if (args != null && args.length == 2) {
String attributeName = args[0];
String attributeValue = args[1];
KStringUtilities.Attribute attribute = KStringUtilities.attributeEnumFromString(attributeName);
if (attribute == null) {
return;
}
LOGD(TAG, "setAttribute Attribute: " + attribute + " " + attributeValue);
switch (attribute) {
case src:
playerController.setEntryMetadata();
// attributeValue is the selected source -- allow override.
attributeValue = getOverrideURL(mConfig.getEntryId(), attributeValue);
playerController.setSrc(attributeValue);
if (mConfig.getContentPreferredBitrate() != -1) {
playerController.setContentPreferredBitrate(mConfig.getContentPreferredBitrate());
}
if (mConfig.getMediaPlayFrom() > 0) {
playerController.setCurrentPlaybackTime((float) mConfig.getMediaPlayFrom());
}
break;
case currentTime:
if (eventListeners != null) {
for (KPEventListener listener : eventListeners) {
listener.onKPlayerStateChanged(this, KPlayerState.SEEKING);
}
}
if (mOnKPStateChangedEventListener != null) {
mOnKPStateChangedEventListener.onKPlayerStateChanged(this, KPlayerState.SEEKING);
}
float time = Float.parseFloat(attributeValue);
playerController.setCurrentPlaybackTime(time);
break;
case visible:
this.triggerEvent("visible", attributeValue);
break;
case licenseUri:
playerController.setLicenseUri(attributeValue);
break;
case nativeAction:
doNativeAction(attributeValue);
break;
case language:
playerController.setLocale(attributeValue);
break;
case doubleClickRequestAds:
String useExternalAdPlayer = getConfig().getConfigValueString("EmbedPlayer.UseExternalAdPlayer");
if("true".equals(useExternalAdPlayer)) {
return;
}
LOGD(TAG, "IMA doubleClickRequestAds initialize:" + attributeValue);
playerController.initIMA(attributeValue, mConfig.getAdMimeType(), mConfig.getAdPreferredBitrate(), mActivity);
break;
case goLive:
(playerController.getPlayer()).switchToLive();
break;
case chromecastAppId:
//getRouterManager().initialize(attributeValue);
LOGD(TAG, "chromecast.initialize:" + attributeValue);
break;
case playerError:
sendOnKPlayerError(attributeValue);
break;
case textTrackSelected:
LOGD(TAG, "textTrackSelected");
if (attributeValue == null){
return;
}
if (mCastProvider != null) {
if ("Off".equalsIgnoreCase(attributeValue)) {
mCastProvider.getCastMediaRemoteControl().switchTextTrack(0);
} else {
for (String lang : mCastProvider.getCastMediaRemoteControl().getTextTracks().keySet()) {
if (lang.equals(attributeValue)) {
mCastProvider.getCastMediaRemoteControl().switchTextTrack(mCastProvider.getCastMediaRemoteControl().getTextTracks().get(lang));
break;
}
}
}
}
if ("Off".equalsIgnoreCase(attributeValue)) {
getTrackManager().switchTrack(TrackType.TEXT, -1);
return;
}
for (int index = 0; index < getTrackManager().getTextTrackList().size(); index++) {
//LOGD(TAG, "<" + getTrackManager().getTextTrackList().get(index) + ">/<" + attributeValue + ">");
if ((getTrackManager().getTextTrackList().get(index).trackLabel).equals(attributeValue)) {
getTrackManager().switchTrack(TrackType.TEXT, index);
return;
}
}
break;
case audioTrackSelected:
LOGD(TAG, "audioTrackSelected");
switchAudioTrack(attributeValue);
break;
}
}
}
private void sendOnKPlayerError(String attributeValue) {
if (eventListeners != null) {
for (KPEventListener listener : eventListeners) {
LOGD(TAG, "sendOnKPlayerError:" + attributeValue);
listener.onKPlayerError(this, new KPError(attributeValue));
}
}
if (mOnKPErrorEventListener != null){
mOnKPErrorEventListener.onKPlayerError(this, new KPError(attributeValue));
}
}
private void switchFlavor(String index) {
try {
index = URLDecoder.decode(index, "UTF-8").replaceAll("\"", ""); // neend to unescape
} catch (UnsupportedEncodingException e) {
return;
}
switchTrack(TrackType.VIDEO,index);
}
private void switchAudioTrack(String index) {
switchTrack(TrackType.AUDIO,index);
}
private void selectClosedCaptions(String index) {
switchTrack(TrackType.TEXT, index);
}
private void switchTrack(TrackType trackType, String index) {
int trackIndex = -1;
try {
trackIndex = Integer.parseInt(index);
if (TrackType.VIDEO.equals(trackType) || TrackType.AUDIO.equals(trackType)) {
if (mCastProvider != null && mCastProvider.isCasting()) {
LOGD(TAG, "switchTrack " + trackType.name() + " is not supported while casting...");
return;
}
if (trackIndex < 0) {
trackIndex = 0;
}
}
} catch (NumberFormatException e) {
LOGE(TAG, "switchTrack " + trackType.name() + " failed parsing index, ignoring request" + index);
return;
}
getTrackManager().switchTrack(trackType, trackIndex);
}
public void setTracksEventListener(KTrackActions.EventListener tracksEventListener){
playerController.setTracksEventListener(tracksEventListener);
}
public void removeTracksEventListener(){
playerController.setTracksEventListener(null);
}
public void setVideoTrackEventListener(KTrackActions.VideoTrackEventListener videoTrackEventListener){
playerController.setVideoTrackEventListener(videoTrackEventListener);
}
public void removeVideoTrackEventListener(){
playerController.setVideoTrackEventListener(null);
}
public void setAudioTrackEventListener(KTrackActions.AudioTrackEventListener audioTrackEventListener){
playerController.setAudioTrackEventListener(audioTrackEventListener);
}
public void removeAusioTrackEventListener(){
playerController.setAudioTrackEventListener(null);
}
public void setTextTrackEventListener(KTrackActions.TextTrackEventListener textTrackEventListener){
playerController.setTextTrackEventListener(textTrackEventListener);
}
public void removeTextTrackEventListener(){
playerController.setTextTrackEventListener(null);
}
private void notifyJsReady() {
mIsJsCallReadyRegistration = true;
if (mCallBackReadyRegistrations != null) {
ArrayList<ReadyEventListener> temp = new ArrayList<ReadyEventListener>(mCallBackReadyRegistrations);
for (ReadyEventListener listener: temp) {
listener.handler();
mCallBackReadyRegistrations.remove(listener);
}
temp = null;
mCallBackReadyRegistrations = null;
}
}
private void notifyKPlayerEvent(String args) {
String[] arguments = KStringUtilities.fetchArgs(args);
if (arguments.length == 2) {
String eventName = arguments[0];
String params = arguments[1];
ArrayList<HashMap<String, EventListener>> listenerArr = mPlayerEventsHash.get(eventName);
if (listenerArr != null) {
for (HashMap<String, EventListener> hash: listenerArr) {
((EventListener)hash.values().toArray()[hash.values().size() - 1]).handler(eventName, params);
}
}
}
}
private void notifyKPlayerEvaluated(String args) {
String[] arguments = KStringUtilities.fetchArgs(args);
if (arguments.length == 2) {
EvaluateListener listener = mPlayerEvaluatedHash.get(arguments[0]);
if (listener != null) {
listener.handler(arguments[1]);
}
} else {
LOGD(TAG, "AsyncEvaluate Error Missing evaluate params");
}
}
private void notifyLayoutReady() {
setChromecastVisiblity();
}
private void toggleFullscreen() {
isFullScreen = !isFullScreen;
if (eventListeners != null) {
for (KPEventListener listener : eventListeners) {
listener.onKPlayerFullScreenToggeled(this, isFullScreen);
}
}
if (mOnKPFullScreenToggledEventListener != null) {
mOnKPFullScreenToggledEventListener.onKPlayerFullScreenToggled(this, isFullScreen);
}
if (eventListeners == null && mOnKPFullScreenToggledEventListener == null) {
defaultFullscreenToggle();
}
}
private void defaultFullscreenToggle() {
int uiOptions = mActivity.getWindow().getDecorView().getSystemUiVisibility();
int newUiOptions = uiOptions;
newUiOptions ^= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
newUiOptions ^= View.SYSTEM_UI_FLAG_FULLSCREEN;
newUiOptions ^= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
if (isFullScreen) {
LOGD(TAG,"Set to onOpenFullScreen");
sendNotification("onOpenFullScreen", null);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}else{
mActivity.getWindow().getDecorView().setSystemUiVisibility(newUiOptions);
}
((AppCompatActivity) mActivity).getSupportActionBar().hide();
} else {
LOGD(TAG,"Set to onCloseFullScreen");
sendNotification("onCloseFullScreen", null);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}else{
mActivity.getWindow().getDecorView().setSystemUiVisibility(newUiOptions);
}
((AppCompatActivity) mActivity).getSupportActionBar().show();
}
// set landscape
// if(fullscreen) activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
// else activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
}
private void sendCCRecieverMessage(String args) {
if (mCastProvider == null) {
return;
}
String decodeArgs = null;
try {
decodeArgs = URLDecoder.decode(args, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
LOGD(TAG, "sendCCRecieverMessage : " + decodeArgs);
((KCastProviderV3Impl)mCastProvider).sendMessage(decodeArgs);
}
private void loadCCMedia() {
// getRouterManager().sendMessage(jsonArgs.getString(0), jsonArgs.getString(1));
}
private void bindPlayerEvents() {
}
private void doNativeAction(String params) {
try {
nativeActionParams = new JSONObject(params);
LOGD(TAG, "doNativeAction: " + nativeActionParams.toString());
String actionTypeJSONValue = null;
actionTypeJSONValue = nativeActionParams.getString("actionType");
if (actionTypeJSONValue.equals(NativeActionType.OPEN_URL.toString())) {
String urlJSONValue = nativeActionParams.getString("url");
openURL(urlJSONValue);
} else {
LOGE(TAG, "Error, action type: " + nativeActionParams.getString("actionType") + " is not supported");
}
if (actionTypeJSONValue.equals(NativeActionType.SHARE.toString())) {
if (nativeActionParams.has(NativeActionType.SHARE_NETWORK.toString())) {
// if (!mShareListener.onShare(videoUrl, type, videoName)){
ShareManager.share(nativeActionParams, mActivity);
//}
}
else{
share(nativeActionParams);
}
return;
}
} catch (JSONException e) {
e.printStackTrace();
}
}
private String buildSupportedMediaFormats() {
Set<KMediaFormat> supportedFormats = KPlayerController.supportedFormats(getContext());
Set<String> drmTypes = new HashSet<>();
Set<String> allTypes = new HashSet<>();
for (KMediaFormat format : supportedFormats) {
if (format.drm != null) {
drmTypes.add(format.shortName);
}
allTypes.add(format.shortName);
}
return new Uri.Builder()
.appendQueryParameter("nativeSdkDrmFormats", TextUtils.join(",", drmTypes))
.appendQueryParameter("nativeSdkAllFormats", TextUtils.join(",", allTypes))
.build().getQuery();
}
// Native actions
private void share(JSONObject shareParams) {
// if(mShareListener != null){
// try {
// String videoUrl = (String)shareParams.get("sharedLink");
// String videoName = (String)shareParams.get("videoName");
// ShareManager.SharingType type = ShareStrategyFactory.getType(shareParams);
// if (!mShareListener.onShare(videoUrl, type, videoName)){
// ShareManager.share(shareParams, mActivity);
// }
// } catch (JSONException e) {
// e.printStackTrace();
// }
// }else {
// ShareManager.share(shareParams, mActivity);
// }
}
public void attachView() {
playerController.attachView();
}
public void detachView() {
playerController.detachView();
}
}