package com.atomjack.vcfp.activities;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.speech.RecognizerIntent;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;
import com.atomjack.shared.NewLogger;
import com.atomjack.shared.PlayerState;
import com.atomjack.shared.Preferences;
import com.atomjack.vcfp.Feedback;
import com.atomjack.vcfp.MediaOptionsDialog;
import com.atomjack.vcfp.PlexHeaders;
import com.atomjack.vcfp.QueryString;
import com.atomjack.vcfp.R;
import com.atomjack.vcfp.VideoControllerView;
import com.atomjack.vcfp.VoiceControlForPlexApplication;
import com.atomjack.vcfp.interfaces.ActiveConnectionHandler;
import com.atomjack.vcfp.interfaces.BitmapHandler;
import com.atomjack.vcfp.interfaces.GenericHandler;
import com.atomjack.vcfp.model.Connection;
import com.atomjack.vcfp.model.PlexClient;
import com.atomjack.vcfp.model.PlexMedia;
import com.atomjack.vcfp.model.PlexVideo;
import com.atomjack.vcfp.net.PlexHttpClient;
import com.atomjack.vcfp.services.PlexSearchService;
import com.atomjack.vcfp.services.SubscriptionService;
import com.google.android.libraries.cast.companionlibrary.utils.Utils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
public class VideoPlayerActivity extends AppCompatActivity
implements MediaPlayer.OnCompletionListener,
MediaPlayer.OnInfoListener,
MediaPlayer.OnPreparedListener,
MediaPlayer.OnErrorListener,
SurfaceHolder.Callback,
VideoControllerView.MediaPlayerControl,
VideoControllerView.BitrateChangeListener {
private NewLogger logger;
protected PlexVideo currentVideo;
protected ArrayList<PlexVideo> playlist;
private SubscriptionService subscriptionService;
private boolean subscriptionServiceIsBound = false;
private int duration;
private int currentVideoIndex = 0; // Index of currently playing video from mediaContainer
protected boolean resume = false;
// When mic input is triggered while playing a video, the video will pause, then resume playback as soon as the activity resumes (comes back from voice input)
private boolean doingMic = false;
protected Handler handler;
protected Feedback feedback;
protected MediaPlayer player;
protected PlayerState currentState = PlayerState.STOPPED;
private String transientToken;
private String session;
// When we're currently playing a video and we get mic input to watch a different video, we don't
// want to finish the activity when the player stops, since we'll have to stop it, then set the new
// data source, then start playback again
private Runnable finishOnPlayerStop = null;
private String currentBitrate = null;
SurfaceView videoSurface;
VideoControllerView controller;
int screenWidth, screenHeight;
private View decorView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
logger = new NewLogger(this);
logger.d("onCreate");
session = VoiceControlForPlexApplication.generateRandomString();
bindSubscriptionService();
feedback = VoiceControlForPlexApplication.getInstance().feedback;
player = new MediaPlayer();
handler = new Handler();
decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
final DisplayMetrics metrics = new DisplayMetrics();
Display display = getWindowManager().getDefaultDisplay();
Method mGetRawH = null, mGetRawW = null;
try {
// For JellyBean 4.2 (API 17) and onward
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
display.getRealMetrics(metrics);
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;
} else {
mGetRawH = Display.class.getMethod("getRawHeight");
mGetRawW = Display.class.getMethod("getRawWidth");
try {
screenWidth = (Integer) mGetRawW.invoke(display);
screenHeight = (Integer) mGetRawH.invoke(display);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (NoSuchMethodException e3) {
e3.printStackTrace();
}
if(getIntent().getAction() != null && getIntent().getAction().equals(com.atomjack.shared.Intent.ACTION_PLAY_LOCAL)) {
handlePlayCommand(getIntent());
} else {
finish();
}
}
private void handlePlayCommand(Intent intent) {
transientToken = intent.getStringExtra(com.atomjack.shared.Intent.EXTRA_TRANSIENT_TOKEN);
playlist = intent.getParcelableArrayListExtra(com.atomjack.shared.Intent.EXTRA_PLAYLIST);
if(playlist == null) {
playlist = new ArrayList<>();
playlist.add(currentVideo);
} else {
for(PlexVideo video : playlist) {
// Overwrite the currentVideo's server if it exists (so it gets the current activeConnection)
if(VoiceControlForPlexApplication.servers.containsKey(video.server.name))
video.server = VoiceControlForPlexApplication.servers.get(video.server.name);
}
}
currentVideoIndex = 0;
currentVideo = playlist.get(currentVideoIndex);
// subscriptionService.setMedia(currentVideo);
resume = intent.getBooleanExtra(com.atomjack.shared.Intent.EXTRA_RESUME, false);
playNewVideo();
}
private View.OnClickListener onPrevious = new View.OnClickListener() {
@Override
public void onClick(View v) {
controller.hide();
currentVideoIndex--;
currentVideo = playlist.get(currentVideoIndex);
// subscriptionService.setMedia(currentVideo);
playNewVideo();
}
};
private View.OnClickListener onNext = new View.OnClickListener() {
@Override
public void onClick(View v) {
controller.hide();
currentVideoIndex++;
currentVideo = playlist.get(currentVideoIndex);
// subscriptionService.setMedia(currentVideo);
playNewVideo();
}
};
private void playNewVideo() {
currentVideo.server.findServerConnection(new ActiveConnectionHandler() {
@Override
public void onSuccess(Connection connection) {
final String url = getTranscodeUrl(currentVideo, connection, transientToken);
logger.d("Using url %s", url);
final boolean shouldPrepare;
if(videoSurface == null) {
setContentView(R.layout.video_player);
videoSurface = (SurfaceView) findViewById(R.id.videoSurface);
shouldPrepare = false;
} else {
handler.removeCallbacks(playerProgressRunnable);
PlexHttpClient.reportProgressToServer(currentVideo, getCurrentPosition(), PlayerState.STOPPED);
if(currentState != PlayerState.STOPPED) {
player.stop();
currentState = PlayerState.STOPPED;
}
shouldPrepare = true;
player.reset();
}
VoiceControlForPlexApplication.getInstance().fetchMediaThumb(currentVideo, screenWidth, screenHeight, currentVideo.isShow() ? currentVideo.grandparentArt : currentVideo.art, currentVideo.getImageKey(PlexMedia.IMAGE_KEY.LOCAL_VIDEO_BACKGROUND), new BitmapHandler() {
@Override
public void onSuccess(Bitmap bitmap) {
final BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(), bitmap);
handler.post(new Runnable() {
@Override
public void run() {
final View videoPlayerLoadingBackground = findViewById(R.id.videoPlayerLoadingBackground);
videoPlayerLoadingBackground.setVisibility(View.VISIBLE);
if(videoPlayerLoadingBackground != null) {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
videoPlayerLoadingBackground.setBackgroundDrawable(bitmapDrawable);
} else {
videoPlayerLoadingBackground.setBackground(bitmapDrawable);
}
}
}
});
}
@Override
public void onFailure() {
// TODO: Handle not finding any active connection here
}
});
Runnable setupPlayer = new Runnable() {
@Override
public void run() {
SurfaceHolder videoHolder = videoSurface.getHolder();
videoHolder.addCallback(VideoPlayerActivity.this);
player.setOnErrorListener(VideoPlayerActivity.this);
player.setOnCompletionListener(VideoPlayerActivity.this);
if(controller == null) {
controller = new VideoControllerView(VideoPlayerActivity.this);
controller.setBitrateChangeListener(VideoPlayerActivity.this);
}
logger.d("Have %d videos", playlist.size());
if(playlist.size() > 1) // Only show the prev/next buttons when there is more than one video to play
controller.setPrevNextListeners(currentVideoIndex > 0 ? onPrevious : null, currentVideoIndex+1 < playlist.size() ? onNext : null);
else
controller.setPrevNextButtonsHidden();
handler.post(new Runnable() {
@Override
public void run() {
setControllerPoster();
}
});
try {
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setDataSource(VideoPlayerActivity.this, Uri.parse(url));
player.setOnPreparedListener(VideoPlayerActivity.this);
if(shouldPrepare)
player.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
}
}
};
// If something is currently playing, we've set it to stop, but want to wait until onCompletion is done before setting up with new media
if(currentState == PlayerState.STOPPED) {
setupPlayer.run();
} else {
finishOnPlayerStop = setupPlayer;
}
}
@Override
public void onFailure(int statusCode) {
// TODO: Handle failure. Feedback?
}
});
}
private void setControllerPoster() {
VoiceControlForPlexApplication.getInstance().fetchMediaThumb(currentVideo,
Utils.convertDpToPixel(this, getResources().getDimension(R.dimen.video_player_poster_width)),
Utils.convertDpToPixel(this, getResources().getDimension(R.dimen.video_player_poster_height)),
currentVideo.isShow() ? currentVideo.grandparentThumb : currentVideo.thumb,
currentVideo.getImageKey(PlexMedia.IMAGE_KEY.LOCAL_VIDEO_THUMB),
new BitmapHandler() {
@Override
public void onSuccess(final Bitmap bitmap) {
handler.post(new Runnable() {
@Override
public void run() {
controller.setPoster(bitmap);
}
});
}
});
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(controller != null && event.getAction() == MotionEvent.ACTION_UP) {
if(controller.isShowing())
controller.hide();
else
controller.show();
}
return false;
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
logger.d("onNewIntent: %s", intent.getAction());
if(intent.getAction() != null) {
if(intent.getAction().equals(com.atomjack.shared.Intent.ACTION_MIC_RESPONSE) || intent.getAction().equals(com.atomjack.shared.Intent.ACTION_VIDEO_DO_PLAYBACK)) {
String command = intent.getStringExtra(com.atomjack.shared.Intent.ACTION_VIDEO_COMMAND);
if(command.equals(com.atomjack.shared.Intent.ACTION_PLAY)) {
start();
} else if(command.equals(com.atomjack.shared.Intent.ACTION_PAUSE)) {
pause();
} else if(command.equals(com.atomjack.shared.Intent.ACTION_STOP)) {
finish();
}
} else if(intent.getAction().equals(com.atomjack.shared.Intent.ACTION_PLAY_LOCAL)) {
handlePlayCommand(intent);
}
}
}
private String getTranscodeUrl(PlexMedia media, Connection connection, String transientToken) {
return getTranscodeUrl(media, connection, transientToken, false);
}
private String getTranscodeUrl(PlexMedia media, Connection connection, String transientToken, boolean subtitles) {
String url = connection.uri;
url += String.format("/%s/:/transcode/universal/%s?", (media instanceof PlexVideo ? "video" : "audio"), (subtitles ? "subtitles" : "start.m3u8"));
QueryString qs = new QueryString("path", String.format("http://127.0.0.1:32400%s", media.key));
qs.add("mediaIndex", "0");
qs.add("partIndex", "0");
qs.add("subtitles", "auto");
qs.add("copyts", "1");
qs.add("subtitleSize", "100");
qs.add("Accept-Language", "en");
qs.add("X-Plex-Client-Profile-Extra", "");
qs.add("X-Plex-Chunked", "1");
qs.add("protocol", "http");
qs.add("offset", "0");
qs.add("fastSeek", "1");
qs.add("directPlay", "0");
qs.add("directStream", "1");
qs.add("videoQuality", "60");
if(currentBitrate == null) {
currentBitrate = VoiceControlForPlexApplication.getInstance().prefs.getString(connection.local ? Preferences.LOCAL_VIDEO_QUALITY_LOCAL : Preferences.LOCAL_VIDEO_QUALITY_REMOTE);
}
qs.add("maxVideoBitrate", VoiceControlForPlexApplication.localVideoQualityOptions.get(currentBitrate)[0]);
qs.add("videoResolution", VoiceControlForPlexApplication.localVideoQualityOptions.get(currentBitrate)[1]);
qs.add("audioBoost", "100");
qs.add("session", session);
qs.add(PlexHeaders.XPlexClientIdentifier, VoiceControlForPlexApplication.getInstance().prefs.getUUID());
qs.add(PlexHeaders.XPlexProduct, VoiceControlForPlexApplication.getInstance().getString(R.string.app_name));
qs.add(PlexHeaders.XPlexDevice, android.os.Build.MODEL);
qs.add(PlexHeaders.XPlexPlatform, "Android");
qs.add("protocol", "hls");
if(transientToken != null)
qs.add(PlexHeaders.XPlexToken, transientToken);
qs.add(PlexHeaders.XPlexPlatformVersion, "1.0");
try {
qs.add(PlexHeaders.XPlexVersion, VoiceControlForPlexApplication.getInstance().getPackageManager().getPackageInfo(VoiceControlForPlexApplication.getInstance().getPackageName(), 0).versionName);
} catch (Exception ex) {
ex.printStackTrace();
}
if(VoiceControlForPlexApplication.getInstance().prefs.getString(Preferences.PLEX_USERNAME) != null)
qs.add(PlexHeaders.XPlexUsername, VoiceControlForPlexApplication.getInstance().prefs.getString(Preferences.PLEX_USERNAME));
return url + qs.toString();
}
@Override
public void onCompletion(MediaPlayer mp) {
logger.d("onCompletion");
if(finishOnPlayerStop == null) {
if(currentVideoIndex+1 < playlist.size()) {
currentState = PlayerState.STOPPED;
onNext.onClick(null);
} else
finish();
} else {
finishOnPlayerStop.run();
finishOnPlayerStop = null;
}
}
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
// logger.d("onInfo: %d, %d", what, extra);
return false;
}
// Implement MediaPlayer.OnPreparedListener
@Override
public void onPrepared(MediaPlayer mp) {
logger.d("onPrepared");
currentState = PlayerState.BUFFERING;
controller.setCurrentVideoQuality(currentBitrate);
controller.setMediaPlayer(this);
controller.setAnchorView((FrameLayout) findViewById(R.id.videoSurfaceContainer));
SurfaceView videoSurface = (SurfaceView)findViewById(R.id.videoSurface);
int videoWidth = player.getVideoWidth();
int videoHeight = player.getVideoHeight();
float videoProportion = (float) videoWidth / (float) videoHeight;
float screenProportion = (float) screenWidth / (float) screenHeight;
android.view.ViewGroup.LayoutParams lp = videoSurface.getLayoutParams();
if (videoProportion > screenProportion) {
lp.width = screenWidth;
lp.height = (int) ((float) screenWidth / videoProportion);
} else {
lp.width = (int) (videoProportion * (float) screenHeight);
lp.height = screenHeight;
}
// logger.d("Setting width/height to %d/%d", lp.width, lp.height);
// logger.d("Setting screen width/height to %d/%d", screenWidth, screenHeight);
videoSurface.setLayoutParams(lp);
if(resume && currentVideo.viewOffset != null) {
logger.d("Seeking to %d before playing", Integer.parseInt(currentVideo.viewOffset) / 1000);
player.seekTo(Integer.parseInt(currentVideo.viewOffset));
}
// Video is ready to start playing, so hide the loading background
final View videoPlayerLoadingBackground = findViewById(R.id.videoPlayerLoadingBackground);
videoPlayerLoadingBackground.setVisibility(View.INVISIBLE);
duration = player.getDuration();
player.start();
player.setOnCompletionListener(this);
player.setOnInfoListener(this);
videoIsPlayingCheck.run();
}
// End MediaPlayer.OnPreparedListener
// Implement MediaPlayer.OnErrorListener
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
logger.d("Media Player Error: %d", what);
if(what == MediaPlayer.MEDIA_ERROR_UNKNOWN) {
feedback.e(R.string.unknown_error_occurred);
} else if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
feedback.e(R.string.error_server_died);
}
return false;
}
// End MediaPlayer.OnErrorListener
@Override
public void onBackPressed() {
// if(player != null)
// player.stop();
super.onBackPressed();
}
@Override
protected void onStop() {
super.onStop();
handler.removeCallbacks(playerProgressRunnable);
PlexHttpClient.reportProgressToServer(currentVideo, getCurrentPosition(), PlayerState.STOPPED);
}
@Override
protected void onDestroy() {
super.onDestroy();
player.stop();
player.release();
logger.d("Stopping transcoder");
currentState = PlayerState.STOPPED;
VoiceControlForPlexApplication.getInstance().sendWearPlaybackChange(currentState, currentVideo);
PlexHttpClient.stopTranscoder(currentVideo.server, session, "video");
}
@Override
protected void onPause() {
super.onPause();
if(player.isPlaying()) {
pause();
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
player.setDisplay(holder);
if(currentState == PlayerState.PAUSED) {
player.start();
handler.postDelayed(playerProgressRunnable, 1000);
} else {
player.prepareAsync();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
// Implement VideoMediaController.MediaPlayerControl
@Override
public void start() {
currentState = PlayerState.PLAYING;
player.start();
VoiceControlForPlexApplication.getInstance().sendWearPlaybackChange(currentState, currentVideo);
}
@Override
public void pause() {
currentState = PlayerState.PAUSED;
player.pause();
VoiceControlForPlexApplication.getInstance().sendWearPlaybackChange(currentState, currentVideo);
}
@Override
public int getDuration() {
return duration;
}
@Override
public int getCurrentPosition() {
try {
return player.getCurrentPosition();
} catch (Exception e) {}
return 0;
}
@Override
public void seekTo(int pos) {
player.seekTo(pos);
}
@Override
public boolean isPlaying() {
try {
return player.isPlaying();
} catch (Exception e) {}
return false;
}
@Override
public int getBufferPercentage() {
return 0;
}
@Override
public boolean canPause() {
return true;
}
@Override
public boolean canSeekBackward() {
return true;
}
@Override
public boolean canSeekForward() {
return true;
}
@Override
public boolean isFullScreen() {
return false;
}
@Override
public void toggleFullScreen() {
}
@Override
protected void onResume() {
super.onResume();
if(doingMic) {
doingMic = false;
player.start();
}
}
@Override
public void doMic() {
if(currentVideo.server != null) {
if(player.isPlaying())
doingMic = true;
pause();
android.content.Intent serviceIntent = new android.content.Intent(this, PlexSearchService.class);
serviceIntent.putExtra(com.atomjack.shared.Intent.EXTRA_SERVER, VoiceControlForPlexApplication.gsonWrite.toJson(currentVideo.server));
serviceIntent.putExtra(com.atomjack.shared.Intent.EXTRA_CLIENT, VoiceControlForPlexApplication.gsonWrite.toJson(PlexClient.getLocalPlaybackClient()));
serviceIntent.putExtra(com.atomjack.shared.Intent.EXTRA_RESUME, resume);
serviceIntent.putExtra(com.atomjack.shared.Intent.EXTRA_FROM_MIC, true);
serviceIntent.putExtra(com.atomjack.shared.Intent.EXTRA_FROM_LOCAL_PLAYER, true);
serviceIntent.putExtra(com.atomjack.shared.Intent.PLAYER, com.atomjack.shared.Intent.PLAYER_VIDEO);
SecureRandom random = new SecureRandom();
serviceIntent.setData(Uri.parse(new BigInteger(130, random).toString(32)));
PendingIntent resultsPendingIntent = PendingIntent.getService(this, 0, serviceIntent, PendingIntent.FLAG_ONE_SHOT);
android.content.Intent listenerIntent = new android.content.Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
listenerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
listenerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, "voice.recognition.test");
listenerIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 5);
listenerIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT, resultsPendingIntent);
listenerIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, getResources().getString(R.string.voice_prompt));
startActivity(listenerIntent);
}
}
@Override
public void doMediaOptions() {
MediaOptionsDialog mediaOptionsDialog = new MediaOptionsDialog(this, currentVideo, PlexClient.getLocalPlaybackClient());
mediaOptionsDialog.setStreamChangeListener(stream -> PlexHttpClient.setStreamActive(currentVideo, stream, (Runnable) () -> currentVideo.server.findServerConnection(new ActiveConnectionHandler() {
@Override
public void onSuccess(final Connection connection) {
currentVideo.setActiveStream(stream);
handler.removeCallbacks(playerProgressRunnable);
player.stop();
PlexHttpClient.stopTranscoder(currentVideo.server, session, "video", new GenericHandler() {
@Override
public void onSuccess() {
String url = getTranscodeUrl(currentVideo, connection, transientToken);
try {
player.reset();
player.setDataSource(VideoPlayerActivity.this, Uri.parse(url));
player.setOnPreparedListener(VideoPlayerActivity.this);
player.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onFailure() {
}
});
}
@Override
public void onFailure(int statusCode) {
}
})));
mediaOptionsDialog.show();
}
@Override
public void onPosterContainerTouch(View v, MotionEvent event) {
onTouchEvent(event);
}
@Override
public void stop() {
currentState = PlayerState.STOPPED;
VoiceControlForPlexApplication.getInstance().sendWearPlaybackChange(currentState, currentVideo);
handler.removeCallbacks(notPurchasedDisconnectTimer);
finish();
}
// End VideoMediaController.MediaPlayerControl
private Runnable videoIsPlayingCheck = new Runnable() {
@Override
public void run() {
if(getDuration() > 0) {
logger.d("Video is playing");
currentState = PlayerState.PLAYING;
VoiceControlForPlexApplication.getInstance().sendWearPlaybackChange(currentState, currentVideo);
handler.postDelayed(playerProgressRunnable, 1000);
if(!VoiceControlForPlexApplication.getInstance().hasLocalmedia()) {
handler.removeCallbacks(notPurchasedDisconnectTimer);
handler.postDelayed(notPurchasedDisconnectTimer, 1000*60); // disconnect in 60 seconds
}
} else {
handler.postDelayed(videoIsPlayingCheck, 100);
}
}
};
private Runnable playerProgressRunnable = new Runnable() {
@Override
public void run() {
PlexHttpClient.reportProgressToServer(currentVideo, getCurrentPosition(), currentState);
currentVideo.viewOffset = Integer.toString(getCurrentPosition());
handler.postDelayed(playerProgressRunnable, 1000);
}
};
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
}
private Runnable notPurchasedDisconnectTimer = new Runnable() {
@Override
public void run() {
logger.d("auto stopping");
stop();
}
};
// Implement BitrateChangeListener
@Override
public void onBitrateChange(String bitrate) {
currentBitrate = bitrate;
playNewVideo();
}
// End Implement BitrateChangeListener
private void bindSubscriptionService() {
bindSubscriptionService(null);
}
private void bindSubscriptionService(Runnable onConnected) {
subscriptionConnection.binding = true;
subscriptionConnection.setOnConnected(onConnected);
Intent subscriptionServiceIntent = new Intent(getApplicationContext(), SubscriptionService.class);
getApplicationContext().bindService(subscriptionServiceIntent, subscriptionConnection, Context.BIND_AUTO_CREATE);
getApplicationContext().startService(subscriptionServiceIntent);
}
private SubscriptionConnection subscriptionConnection = new SubscriptionConnection();
class SubscriptionConnection implements ServiceConnection {
private Runnable runnable;
private boolean binding = false;
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binding = false;
SubscriptionService.SubscriptionBinder binder = (SubscriptionService.SubscriptionBinder)service;
subscriptionService = binder.getService();
subscriptionServiceIsBound = true;
logger.d("Got subscription service, subscribed: %s", subscriptionService.isSubscribed());
if(runnable != null)
runnable.run();
runnable = null;
}
@Override
public void onServiceDisconnected(ComponentName name) {
logger.d("onServiceDisconnected");
subscriptionServiceIsBound = false;
}
public void setOnConnected(Runnable runnable) {
this.runnable = runnable;
}
}
}