package de.luhmer.owncloudnewsreader;
import android.animation.Animator;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.FragmentTransaction;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.VisibleForTesting;
import android.support.v4.view.GravityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.TypedValue;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.Animation;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayerFragment;
import com.sothree.slidinguppanel.SlidingUpPanelLayout;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import java.io.File;
import butterknife.Bind;
import butterknife.ButterKnife;
import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm;
import de.luhmer.owncloudnewsreader.database.model.RssItem;
import de.luhmer.owncloudnewsreader.events.podcast.PodcastCompletedEvent;
import de.luhmer.owncloudnewsreader.events.podcast.RegisterVideoOutput;
import de.luhmer.owncloudnewsreader.events.podcast.RegisterYoutubeOutput;
import de.luhmer.owncloudnewsreader.events.podcast.UpdatePodcastStatusEvent;
import de.luhmer.owncloudnewsreader.events.podcast.VideoDoubleClicked;
import de.luhmer.owncloudnewsreader.helper.SizeAnimator;
import de.luhmer.owncloudnewsreader.helper.TeslaUnreadManager;
import de.luhmer.owncloudnewsreader.interfaces.IPlayPausePodcastClicked;
import de.luhmer.owncloudnewsreader.model.MediaItem;
import de.luhmer.owncloudnewsreader.model.PodcastItem;
import de.luhmer.owncloudnewsreader.services.PodcastDownloadService;
import de.luhmer.owncloudnewsreader.services.PodcastPlaybackService;
import de.luhmer.owncloudnewsreader.services.podcast.PlaybackService;
import de.luhmer.owncloudnewsreader.view.PodcastSlidingUpPanelLayout;
import de.luhmer.owncloudnewsreader.view.ZoomableRelativeLayout;
import de.luhmer.owncloudnewsreader.widget.WidgetProvider;
public class PodcastFragmentActivity extends AppCompatActivity implements IPlayPausePodcastClicked {
private static final String TAG = PodcastFragmentActivity.class.getCanonicalName();
private PodcastPlaybackService mPodcastPlaybackService;
private boolean mBound = false;
private EventBus eventBus;
private PodcastFragment mPodcastFragment;
private int appHeight;
private int appWidth;
@Bind(R.id.videoPodcastSurfaceWrapper) ZoomableRelativeLayout rlVideoPodcastSurfaceWrapper;
@Bind(R.id.sliding_layout) PodcastSlidingUpPanelLayout sliding_layout;
//YouTubePlayerFragment youtubeplayerfragment;
@Override
protected void onPostCreate(Bundle savedInstanceState) {
eventBus = EventBus.getDefault();
ButterKnife.bind(this);
//youtubeplayerfragment = (YouTubePlayerFragment)getFragmentManager().findFragmentById(R.id.youtubeplayerfragment);
ViewTreeObserver vto = rlVideoPodcastSurfaceWrapper.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
rlVideoPodcastSurfaceWrapper.readVideoPosition();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
rlVideoPodcastSurfaceWrapper.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
rlVideoPodcastSurfaceWrapper.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
});
rlVideoPodcastSurfaceWrapper.setVisibility(View.INVISIBLE);
UpdatePodcastView();
if(isMyServiceRunning(PodcastPlaybackService.class, this)) {
Intent intent = new Intent(this, PodcastPlaybackService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
super.onPostCreate(savedInstanceState);
}
@Override
protected void onStop() {
super.onStop();
unbindPodcastService();
}
private void unbindPodcastService() {
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
if(hasWindowFocus) {
int currentOrientation = getResources().getConfiguration().orientation;
if (currentOrientation != lastOrientation) {
sliding_layout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
lastOrientation = currentOrientation;
}
}
super.onWindowFocusChanged(hasWindowFocus);
}
int lastOrientation = -1;
@Override
protected void onResume() {
eventBus.register(this);
if(mPodcastPlaybackService != null && !mPodcastPlaybackService.isActive()) {
sliding_layout.setPanelHeight(0);
sliding_layout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
}
super.onResume();
}
@Override
protected void onPause() {
Log.d(TAG, "onPause");
eventBus.unregister(this);
//TODO THIS IS NEVER REACHED!
isVideoViewVisible = false;
videoViewInitialized = false;
eventBus.post(new RegisterVideoOutput(null, null));
eventBus.post(new RegisterYoutubeOutput(null, false));
rlVideoPodcastSurfaceWrapper.setVisibility(View.GONE);
rlVideoPodcastSurfaceWrapper.removeAllViews();
TeslaUnreadManager.PublishUnreadCount(this);
WidgetProvider.UpdateWidget(this);
super.onPause();
}
public static boolean isMyServiceRunning(Class<?> serviceClass, Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
PodcastPlaybackService.LocalBinder binder = (PodcastPlaybackService.LocalBinder) service;
mPodcastPlaybackService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
public MediaItem getCurrentPlayingPodcast() {
if(mPodcastPlaybackService != null)
return mPodcastPlaybackService.getCurrentlyPlayingPodcast();
return null;
}
public PodcastSlidingUpPanelLayout getSlidingLayout() {
return sliding_layout;
}
public boolean handlePodcastBackPressed() {
if(mPodcastFragment != null && sliding_layout.getPanelState().equals(SlidingUpPanelLayout.PanelState.EXPANDED)) {
if (!mPodcastFragment.onBackPressed())
sliding_layout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
return true;
}
return false;
}
protected void UpdatePodcastView() {
if(mPodcastFragment != null) {
getSupportFragmentManager().beginTransaction().remove(mPodcastFragment).commitAllowingStateLoss();
}
mPodcastFragment = PodcastFragment.newInstance();
getSupportFragmentManager().beginTransaction()
.replace(R.id.podcast_frame, mPodcastFragment)
.commitAllowingStateLoss();
if(!currentlyPlaying)
sliding_layout.setPanelHeight(0);
}
boolean currentlyPlaying = false;
boolean videoViewInitialized = false;
boolean isVideoViewVisible = true;
@Subscribe
public void onEvent(UpdatePodcastStatusEvent podcast) {
boolean playStateChanged = currentlyPlaying;
//If file is loaded or preparing and podcast is paused/not running expand the view
currentlyPlaying = podcast.getStatus() == PlaybackService.Status.PLAYING
|| podcast.getStatus() == PlaybackService.Status.PAUSED;
//Check if state was changed
playStateChanged = playStateChanged != currentlyPlaying;
// If preparing or state changed and is now playing or paused
if(podcast.getStatus() == PlaybackService.Status.PREPARING
|| (playStateChanged
&& (podcast.getStatus() == PlaybackService.Status.PLAYING
|| podcast.getStatus() == PlaybackService.Status.PAUSED
|| podcast.getStatus() == PlaybackService.Status.STOPPED))) {
//Expand view
sliding_layout.setPanelHeight((int) dipToPx(68));
Log.v(TAG, "expanding podcast view!");
} else if(playStateChanged) {
//Hide view
sliding_layout.setPanelHeight(0);
currentlyPlaying = false;
Log.v(TAG, "collapsing podcast view!");
}
if (podcast.isVideoFile() && podcast.getVideoType() == PlaybackService.VideoType.Video) {
if ((!isVideoViewVisible || !videoViewInitialized) && rlVideoPodcastSurfaceWrapper.isPositionReady()) {
rlVideoPodcastSurfaceWrapper.removeAllViews();
videoViewInitialized = true;
isVideoViewVisible = true;
rlVideoPodcastSurfaceWrapper.setVisibility(View.VISIBLE);
//AlphaAnimator.AnimateVisibilityChange(rlVideoPodcastSurfaceWrapper, View.VISIBLE);
SurfaceView surfaceView = new SurfaceView(this);
surfaceView.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
rlVideoPodcastSurfaceWrapper.addView(surfaceView);
eventBus.post(new RegisterVideoOutput(surfaceView, rlVideoPodcastSurfaceWrapper));
togglePodcastVideoViewAnimation();
}
} else if(podcast.getVideoType() == PlaybackService.VideoType.YouTube){
if(!videoViewInitialized) {
isVideoViewVisible = true;
videoViewInitialized = true;
rlVideoPodcastSurfaceWrapper.removeAllViews();
rlVideoPodcastSurfaceWrapper.setVisibility(View.VISIBLE);
togglePodcastVideoViewAnimation();
final int YOUTUBE_CONTENT_VIEW_ID = 10101010;
FrameLayout frame = new FrameLayout(this);
frame.setId(YOUTUBE_CONTENT_VIEW_ID);
rlVideoPodcastSurfaceWrapper.addView(frame);
//setContentView(frame, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
YouTubePlayerFragment youTubePlayerFragment = YouTubePlayerFragment.newInstance();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(YOUTUBE_CONTENT_VIEW_ID, youTubePlayerFragment).commit();
youTubePlayerFragment.initialize("AIzaSyA2OHKWvF_hRVtPmLcwnO8yF6-iah2hjbk", new YouTubePlayer.OnInitializedListener() {
@Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean wasRestored) {
eventBus.post(new RegisterYoutubeOutput(youTubePlayer, wasRestored));
togglePodcastVideoViewAnimation();
}
@Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
Toast.makeText(PodcastFragmentActivity.this, "Error while playing youtube video! (InitializationFailure)", Toast.LENGTH_LONG).show();
}
});
}
} else {
isVideoViewVisible = false;
videoViewInitialized = false;
eventBus.post(new RegisterVideoOutput(null, null));
eventBus.post(new RegisterYoutubeOutput(null, false));
rlVideoPodcastSurfaceWrapper.setVisibility(View.GONE);
//AlphaAnimator.AnimateVisibilityChange(rlVideoPodcastSurfaceWrapper, View.GONE);
rlVideoPodcastSurfaceWrapper.removeAllViews();
}
}
@Subscribe
public void onEvent(PodcastCompletedEvent podcastCompletedEvent) {
sliding_layout.setPanelHeight(0);
sliding_layout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
currentlyPlaying = false;
}
private static final int animationTime = 300; //Milliseconds
float oldScaleFactor = 1;
boolean isFullScreen = false;
float scaleFactor = 1;
boolean useAnimation = false;
@Subscribe
public void onEvent(VideoDoubleClicked videoDoubleClicked) {
appHeight = getWindow().getDecorView().findViewById(android.R.id.content).getHeight();
appWidth = getWindow().getDecorView().findViewById(android.R.id.content).getWidth();
if(isFullScreen) {
rlVideoPodcastSurfaceWrapper.setDisableScale(false);
togglePodcastVideoViewAnimation();
//showSystemUI();
} else {
//hideSystemUI();
rlVideoPodcastSurfaceWrapper.setDisableScale(true);
oldScaleFactor = rlVideoPodcastSurfaceWrapper.getScaleFactor();
final View view = rlVideoPodcastSurfaceWrapper;
final float oldHeight = view.getLayoutParams().height;
final float oldWidth = view.getLayoutParams().width;
//view.setPivotX(oldWidth/2);
//view.setPivotY(oldHeight/2);
/*
Display display = getWindowManager().getDefaultDisplay();
float width = display.getWidth(); // deprecated
float height = display.getHeight(); // deprecated
*/
scaleFactor = appWidth / (float) view.getWidth();
float newHeightTemp = oldHeight * scaleFactor;
float newWidthTemp = oldWidth * scaleFactor;
//view.animate().scaleX(scaleFactor).scaleY(scaleFactor).setDuration(100);
//scaleView(view, 1f, scaleFactor, 1f, scaleFactor);
if(newHeightTemp > appHeight) { //Could happen on Tablets or in Landscape Mode
scaleFactor = appHeight / (float) view.getHeight();
newHeightTemp = oldHeight * scaleFactor;
newWidthTemp = oldWidth * scaleFactor;
}
final float newHeight = newHeightTemp;
final float newWidth = newWidthTemp;
float newXPosition = rlVideoPodcastSurfaceWrapper.getVideoXPosition() + (int) getResources().getDimension(R.dimen.activity_vertical_margin);// (appWidth / 2) + dipToPx(10);
float newYPosition = (appHeight/2) + ((newHeight/2) - oldHeight);
useAnimation = true;
view.animate().x(newXPosition).y(newYPosition).setDuration(animationTime).setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
if(useAnimation) {
view.startAnimation(new SizeAnimator(view, newWidth, newHeight, oldWidth, oldHeight, animationTime).sizeAnimator);
}
useAnimation = false;
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
//rlVideoPodcastSurfaceWrapper.animate().scaleX(scaleFactor).scaleY(scaleFactor).x(newXPosition).y(newYPosition).setDuration(500).setListener(onResizeListener);
//surfaceView.animate().scaleX(scaleFactor).scaleY(scaleFactor).setDuration(500);
//oldScaleFactor
//scaleFactor = dipToPx(oldWidth) / newWidth;
//scaleFactor = (1/oldScaleFactor) * dipToPx(oldWidth) / newWidth;
//scaleFactor = oldWidth / newWidth;
scaleFactor = 1/scaleFactor;
}
isFullScreen = !isFullScreen;
}
public void togglePodcastVideoViewAnimation() {
boolean isLeftSliderOpen = false;
if(this instanceof NewsReaderListActivity && ((NewsReaderListActivity) this).drawerLayout != null) {
isLeftSliderOpen = ((NewsReaderListActivity) this).drawerLayout.isDrawerOpen(GravityCompat.START);
}
int podcastMediaControlHeightDp = pxToDp((int) getResources().getDimension(R.dimen.podcast_media_control_height));
if(sliding_layout.getPanelState().equals(SlidingUpPanelLayout.PanelState.EXPANDED)) { //On Tablets
animateToPosition(podcastMediaControlHeightDp);
} else if(isLeftSliderOpen) {
animateToPosition(0);
} else {
animateToPosition(64);
}
}
public static int pxToDp(int px)
{
return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
public void animateToPosition(final int yPosition) {
appHeight = getWindow().getDecorView().findViewById(android.R.id.content).getHeight();
appWidth = getWindow().getDecorView().findViewById(android.R.id.content).getWidth();
final View view = rlVideoPodcastSurfaceWrapper; //surfaceView
if(scaleFactor != 1) {
int oldHeight = view.getLayoutParams().height;
int oldWidth = view.getLayoutParams().width;
int newHeight = view.getLayoutParams().height *= scaleFactor;
int newWidth = view.getLayoutParams().width *= scaleFactor;
scaleFactor = 1;
Animation animator = new SizeAnimator(view, newWidth, newHeight, oldWidth, oldHeight, animationTime).sizeAnimator;
animator.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
animateToPosition(yPosition);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
view.startAnimation(animator);
} else {
int absoluteYPosition = appHeight - view.getHeight() - (int) getResources().getDimension(R.dimen.activity_vertical_margin) - (int) dipToPx(yPosition);
float xPosition = rlVideoPodcastSurfaceWrapper.getVideoXPosition();
//TODO podcast video is only working for newer android versions
view.animate().x(xPosition).y(absoluteYPosition).setDuration(animationTime);
}
/*
int height = (int)(view.getHeight() * scaleFactor);
int width = (int)(view.getWidth() * scaleFactor);
view.setScaleX(oldScaleFactor);
view.setScaleY(oldScaleFactor);
view.getLayoutParams().height = height;
view.getLayoutParams().width = width;
*/
oldScaleFactor = 1;
}
float dipToPx(float dip) {
Resources r = getResources();
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, r.getDisplayMetrics());
return px;
}
@VisibleForTesting
public void openMediaItem(final MediaItem mediaItem) {
Intent intent = new Intent(this, PodcastPlaybackService.class);
intent.putExtra(PodcastPlaybackService.MEDIA_ITEM, mediaItem);
startService(intent);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
public void openPodcast(final RssItem rssItem) {
final PodcastItem podcastItem = DatabaseConnectionOrm.ParsePodcastItemFromRssItem(this, rssItem);
File file = new File(PodcastDownloadService.getUrlToPodcastFile(this, podcastItem.link, false));
if(file.exists()) {
podcastItem.link = file.getAbsolutePath();
openMediaItem(podcastItem);
} else if(!podcastItem.offlineCached) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this)
.setNegativeButton("Abort", null)
.setNeutralButton("Download", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
PodcastDownloadService.startPodcastDownload(PodcastFragmentActivity.this, podcastItem);
Toast.makeText(PodcastFragmentActivity.this, "Starting download of podcast. Please wait..", Toast.LENGTH_SHORT).show();
}
})
.setTitle("Podcast")
.setMessage("Choose if you want to download or stream the selected podcast");
alertDialog.setPositiveButton("Stream", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
openMediaItem(podcastItem);
}
});
alertDialog.show();
}
}
@Override
public void pausePodcast() {
mPodcastPlaybackService.pause();
}
}