diff --git a/build.gradle b/build.gradle index 0d7369f..a652e81 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,6 @@ buildscript { classpath "com.android.tools.build:gradle:$versions.gradlePlugin" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin" classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$versions.bintrayPlugin" - classpath "com.github.dcendents:android-maven-gradle-plugin:$versions.mavenPlugin" } } diff --git a/dependencies.gradle b/dependencies.gradle index 89dbe71..2e2a5a5 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -16,17 +16,17 @@ ext.versions = [ minSdk : 19, - compileSdk : 28, + compileSdk : 29, buildTools : '28.0.3', - publishVersion : '0.0.8', + publishVersion : '1.1.3', publishVersionCode: 1, - gradlePlugin : '3.4.1', - bintrayPlugin : '1.7.3', + gradlePlugin : '3.4.2', + bintrayPlugin : '1.8.4', mavenPlugin : '1.4.1', supportLib : '28.0.0', constraintLayout : '1.1.3', espresso : '3.0.1', - kotlin : '1.3.31', + kotlin : '1.3.41', leakCanary : '1.6.1' ] \ No newline at end of file diff --git a/library/release.gradle b/library/release.gradle index 3a7f837..63318a6 100644 --- a/library/release.gradle +++ b/library/release.gradle @@ -14,14 +14,13 @@ * limitations under the License. */ -apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' apply from: 'keystore.gradle' ext { publishedGroupId = 'bg.devlabs.fullscreenvideoview' artifactId = 'library' - libraryVersion = '1.1.2' + libraryVersion = '1.1.3' } version = libraryVersion @@ -42,16 +41,13 @@ bintray { } } -install { - repositories.mavenInstaller { - pom.project { - packaging 'aar' - groupId publishedGroupId - artifactId artifactId - version libraryVersion - name artifactId - } - } +project.ext { + mavDevelopers = ["SP":"Slavi Petrov"] + mavSiteUrl = "https://github.com/dev-labs-bg/fullscreen-video-view" + mavGitUrl = mavSiteUrl + '.git' + mavProjectName = 'FullscreenVideoView' + mavLibraryLicenses = ["Apache-2.0":'http://www.apache.org/licenses/LICENSE-2.0.txt'] + mavLibraryDescription = "FullscreenVideoView is a custom VideoView Android library which makes loading, setting up and going fullscreen for video views easy." } if (project.hasProperty("android")) { @@ -87,4 +83,6 @@ task javadocJar(type: Jar, dependsOn: javadoc) { artifacts { archives javadocJar archives sourcesJar -} \ No newline at end of file +} + +apply from: 'https://raw.githubusercontent.com/sky-uk/gradle-maven-plugin/master/gradle-mavenizer.gradle' \ No newline at end of file diff --git a/library/src/main/java/bg/devlabs/fullscreenvideoview/Builder.java b/library/src/main/java/bg/devlabs/fullscreenvideoview/Builder.java index 4742392..ecaa04a 100644 --- a/library/src/main/java/bg/devlabs/fullscreenvideoview/Builder.java +++ b/library/src/main/java/bg/devlabs/fullscreenvideoview/Builder.java @@ -26,6 +26,7 @@ import java.io.File; +import bg.devlabs.fullscreenvideoview.listener.mediacontroller.MediaControllerListener; import bg.devlabs.fullscreenvideoview.listener.OnErrorListener; import bg.devlabs.fullscreenvideoview.orientation.LandscapeOrientation; import bg.devlabs.fullscreenvideoview.orientation.OrientationManager; @@ -371,4 +372,14 @@ public Builder addOnErrorListener(OnErrorListener onErrorListener) { fullscreenVideoView.addOnErrorListener(onErrorListener); return this; } + + /** + * Adds a listener for media controller events. + * + * @return the builder instance + */ + public Builder mediaControllerListener(MediaControllerListener mediaControllerListener) { + controller.setOnMediaControllerListener(mediaControllerListener); + return this; + } } diff --git a/library/src/main/java/bg/devlabs/fullscreenvideoview/ButtonManager.java b/library/src/main/java/bg/devlabs/fullscreenvideoview/ButtonManager.java index bb10a8e..f1bef1c 100644 --- a/library/src/main/java/bg/devlabs/fullscreenvideoview/ButtonManager.java +++ b/library/src/main/java/bg/devlabs/fullscreenvideoview/ButtonManager.java @@ -20,12 +20,17 @@ import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.support.v4.content.ContextCompat; +import android.view.View; import android.widget.ImageButton; import android.widget.TextView; import java.lang.ref.WeakReference; +import bg.devlabs.fullscreenvideoview.playbackspeed.PlaybackSpeedPopupMenuListener; import bg.devlabs.fullscreenvideoview.orientation.OrientationManager; +import bg.devlabs.fullscreenvideoview.playbackspeed.PlaybackSpeedOptions; + +import static android.view.View.INVISIBLE; /** * Created by Slavi Petrov on 04.06.2018 @@ -45,31 +50,49 @@ class ButtonManager { private WeakReference ffwdButton; private WeakReference rewButton; private WeakReference fullscreenButton; - private WeakReference playbackSpeedButton; - + // Other private WeakReference orientationHelper; private WeakReference videoMediaPlayer; - - ButtonManager(Context context, ImageButton startPauseButton, ImageButton ffwdButton, - ImageButton rewButton, ImageButton fullscreenButton, TextView playbackSpeedButton) { - this.exitFullscreenDrawable = ContextCompat.getDrawable(context, - R.drawable.ic_fullscreen_exit_white_48dp); - this.enterFullscreenDrawable = ContextCompat.getDrawable(context, - R.drawable.ic_fullscreen_white_48dp); - this.playDrawable = ContextCompat.getDrawable(context, - R.drawable.ic_play_arrow_white_48dp); - this.pauseDrawable = ContextCompat.getDrawable(context, - R.drawable.ic_pause_white_48dp); - this.fastForwardDrawable = ContextCompat.getDrawable(context, - R.drawable.ic_fast_forward_white_48dp); - this.rewindDrawable = ContextCompat.getDrawable(context, - R.drawable.ic_fast_rewind_white_48dp); + private PlaybackSpeedManager playbackSpeedManager; + + ButtonManager(Context context, + ImageButton startPauseButton, + ImageButton ffwdButton, + ImageButton rewButton, + ImageButton fullscreenButton, + TextView playbackSpeedButton) { + + this.exitFullscreenDrawable = ContextCompat.getDrawable( + context, + R.drawable.ic_fullscreen_exit_white_48dp + ); + this.enterFullscreenDrawable = ContextCompat.getDrawable( + context, + R.drawable.ic_fullscreen_white_48dp + ); + this.playDrawable = ContextCompat.getDrawable( + context, + R.drawable.ic_play_arrow_white_48dp + ); + this.pauseDrawable = ContextCompat.getDrawable( + context, + R.drawable.ic_pause_white_48dp + ); + this.fastForwardDrawable = ContextCompat.getDrawable( + context, + R.drawable.ic_fast_forward_white_48dp + ); + this.rewindDrawable = ContextCompat.getDrawable( + context, + R.drawable.ic_fast_rewind_white_48dp + ); this.startPauseButton = new WeakReference<>(startPauseButton); this.ffwdButton = new WeakReference<>(ffwdButton); this.rewButton = new WeakReference<>(rewButton); this.fullscreenButton = new WeakReference<>(fullscreenButton); - this.playbackSpeedButton = new WeakReference<>(playbackSpeedButton); + + playbackSpeedManager = new PlaybackSpeedManager(context, playbackSpeedButton); } public void setupDrawables(TypedArray typedArray) { @@ -97,14 +120,19 @@ private void setupRewindButton(TypedArray a) { private void setupFullscreenButton(TypedArray a) { Drawable enterDrawable = a.getDrawable( - R.styleable.VideoControllerView_enter_fullscreen_drawable); + R.styleable.VideoControllerView_enter_fullscreen_drawable + ); + if (enterDrawable != null) { enterFullscreenDrawable = enterDrawable; } + fullscreenButton.get().setImageDrawable(enterFullscreenDrawable); Drawable exitDrawable = a.getDrawable( - R.styleable.VideoControllerView_exit_fullscreen_drawable); + R.styleable.VideoControllerView_exit_fullscreen_drawable + ); + if (exitDrawable != null) { setExitFullscreenDrawable(exitDrawable); } @@ -204,6 +232,77 @@ public void setVideoMediaPlayer(VideoMediaPlayer videoMediaPlayer) { } public void updatePlaybackSpeedText(String text) { - playbackSpeedButton.get().setText(text); + playbackSpeedManager.setPlaybackSpeedText(text); + } + + public void setFullscreenButtonClickListener(View.OnClickListener onClickListener) { + fullscreenButton.get().requestFocus(); + fullscreenButton.get().setOnClickListener(onClickListener); + } + + public void setStartPauseButtonClickListener(View.OnClickListener onClickListener) { + startPauseButton.get().requestFocus(); + startPauseButton.get().setOnClickListener(onClickListener); + } + + public void hideFullscreenButton() { + fullscreenButton.get().setVisibility(View.GONE); + } + + public void setupButtonsVisibility() { + if (startPauseButton != null && !videoMediaPlayer.get().canPause()) { + startPauseButton.get().setEnabled(false); + startPauseButton.get().setVisibility(INVISIBLE); + } + + if (rewButton != null && !videoMediaPlayer.get().showSeekBackwardButton()) { + rewButton.get().setEnabled(false); + rewButton.get().setVisibility(INVISIBLE); + } + + if (ffwdButton != null && !videoMediaPlayer.get().showSeekForwardButton()) { + ffwdButton.get().setEnabled(false); + ffwdButton.get().setVisibility(INVISIBLE); + } + + playbackSpeedManager.hidePlaybackButton(videoMediaPlayer.get().showPlaybackSpeedButton()); + } + + public void requestStartPauseButtonFocus() { + if (startPauseButton != null) { + startPauseButton.get().requestFocus(); + } + } + + public void setButtonsEnabled(boolean isEnabled) { + if (startPauseButton != null) { + startPauseButton.get().setEnabled(isEnabled); + } + + if (ffwdButton != null) { + ffwdButton.get().setEnabled(isEnabled); + } + + if (rewButton != null) { + rewButton.get().setEnabled(isEnabled); + } + + playbackSpeedManager.setPlaybackSpeedButtonEnabled(isEnabled); + } + + public void setFfwdButtonOnClickListener(View.OnClickListener onClickListener) { + ffwdButton.get().setOnClickListener(onClickListener); + } + + public void setRewButtonOnClickListener(View.OnClickListener onClickListener) { + rewButton.get().setOnClickListener(onClickListener); + } + + public void setPlaybackSpeedPopupMenuListener(PlaybackSpeedPopupMenuListener listener) { + playbackSpeedManager.setPlaybackSpeedButtonOnClickListener(listener); + } + + public void setPlaybackSpeedOptions(PlaybackSpeedOptions playbackSpeedOptions) { + playbackSpeedManager.setPlaybackSpeedOptions(playbackSpeedOptions); } } diff --git a/library/src/main/java/bg/devlabs/fullscreenvideoview/FullscreenVideoView.java b/library/src/main/java/bg/devlabs/fullscreenvideoview/FullscreenVideoView.java index 568edf0..efcf6a6 100644 --- a/library/src/main/java/bg/devlabs/fullscreenvideoview/FullscreenVideoView.java +++ b/library/src/main/java/bg/devlabs/fullscreenvideoview/FullscreenVideoView.java @@ -92,7 +92,8 @@ public FullscreenVideoView(@NonNull Context context, @Nullable AttributeSet attr init(attrs); } - public FullscreenVideoView(@NonNull Context context, @Nullable AttributeSet attrs, + public FullscreenVideoView(@NonNull Context context, + @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); diff --git a/library/src/main/java/bg/devlabs/fullscreenvideoview/PlaybackSpeedManager.java b/library/src/main/java/bg/devlabs/fullscreenvideoview/PlaybackSpeedManager.java new file mode 100644 index 0000000..91255d0 --- /dev/null +++ b/library/src/main/java/bg/devlabs/fullscreenvideoview/PlaybackSpeedManager.java @@ -0,0 +1,95 @@ +/* + * Copyright 2017 Dev Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bg.devlabs.fullscreenvideoview; + +import android.content.Context; +import android.support.v7.widget.PopupMenu; +import android.view.View; +import android.widget.TextView; + +import bg.devlabs.fullscreenvideoview.playbackspeed.PlaybackSpeedPopupMenuListener; +import bg.devlabs.fullscreenvideoview.playbackspeed.OnPlaybackSpeedSelectedListener; +import bg.devlabs.fullscreenvideoview.playbackspeed.PlaybackSpeedOptions; +import bg.devlabs.fullscreenvideoview.playbackspeed.PlaybackSpeedPopupMenu; + +import static android.view.View.INVISIBLE; + +/** + * Created by Slavi Petrov on 14.08.2019 + * Dev Labs + * slavi@devlabs.bg + */ +public class PlaybackSpeedManager { + + private TextView playbackSpeedButton; + private PlaybackSpeedPopupMenu popupMenu; + + PlaybackSpeedManager(Context context, TextView playbackSpeedButton) { + this.playbackSpeedButton = playbackSpeedButton; + // Initialize the PopupMenu + popupMenu = new PlaybackSpeedPopupMenu(context, playbackSpeedButton); + } + + void setPlaybackSpeedButtonOnClickListener( + final PlaybackSpeedPopupMenuListener playbackSpeedPopupMenuListener + ) { + playbackSpeedButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + popupMenu.setOnSpeedSelectedListener(new OnPlaybackSpeedSelectedListener() { + @Override + public void onSpeedSelected(float speed, String text) { + playbackSpeedPopupMenuListener.onSpeedSelected(speed, text); + } + }); + + popupMenu.setOnDismissListener(new PopupMenu.OnDismissListener() { + @Override + public void onDismiss(PopupMenu menu) { + playbackSpeedPopupMenuListener.onPopupMenuDismissed(); + } + }); + + // Show the PopupMenu + popupMenu.show(); + + playbackSpeedPopupMenuListener.onPopupMenuShown(); + } + }); + } + + public void setPlaybackSpeedButtonEnabled(boolean isEnabled) { + if (playbackSpeedButton != null) { + playbackSpeedButton.setEnabled(isEnabled); + } + } + + public void hidePlaybackButton(boolean showPlaybackSpeedButton) { + if (playbackSpeedButton != null && !showPlaybackSpeedButton) { + playbackSpeedButton.setEnabled(false); + playbackSpeedButton.setVisibility(INVISIBLE); + } + } + + public void setPlaybackSpeedText(String text) { + playbackSpeedButton.setText(text); + } + + public void setPlaybackSpeedOptions(PlaybackSpeedOptions playbackSpeedOptions) { + popupMenu.setPlaybackSpeedOptions(playbackSpeedOptions); + } +} diff --git a/library/src/main/java/bg/devlabs/fullscreenvideoview/VideoControllerView.java b/library/src/main/java/bg/devlabs/fullscreenvideoview/VideoControllerView.java index 0e44563..c69038b 100644 --- a/library/src/main/java/bg/devlabs/fullscreenvideoview/VideoControllerView.java +++ b/library/src/main/java/bg/devlabs/fullscreenvideoview/VideoControllerView.java @@ -28,7 +28,6 @@ import android.os.Message; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; -import android.support.v7.widget.PopupMenu; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; @@ -43,10 +42,10 @@ import java.lang.ref.WeakReference; import java.util.Locale; +import bg.devlabs.fullscreenvideoview.listener.mediacontroller.MediaControllerListener; +import bg.devlabs.fullscreenvideoview.playbackspeed.PlaybackSpeedPopupMenuListener; import bg.devlabs.fullscreenvideoview.orientation.OrientationManager; -import bg.devlabs.fullscreenvideoview.playbackspeed.OnPlaybackSpeedSelectedListener; import bg.devlabs.fullscreenvideoview.playbackspeed.PlaybackSpeedOptions; -import bg.devlabs.fullscreenvideoview.playbackspeed.PlaybackSpeedPopupMenu; import static bg.devlabs.fullscreenvideoview.Constants.VIEW_TAG_CLICKED; @@ -90,32 +89,9 @@ class VideoControllerView extends FrameLayout { private TextView endTime; private TextView currentTime; private boolean isDragging; - private PlaybackSpeedPopupMenu popupMenu; @Nullable private Handler handler = new VideoControllerView.MessageHandler(this); private SeekBar progress; - private ImageButton startPauseButton; - private ImageButton fullscreenButton; - private ImageButton ffwdButton; - private ImageButton rewButton; - private TextView playbackSpeedButton; - @Nullable - private View.OnClickListener pauseListener = new OnClickListener() { - @Override - public void onClick(View v) { - doPauseResume(); - show(DEFAULT_TIMEOUT); - } - }; - @Nullable - private View.OnClickListener fullscreenListener = new OnClickListener() { - @Override - public void onClick(View view) { - view.setTag(VIEW_TAG_CLICKED); - doToggleFullscreen(); - show(DEFAULT_TIMEOUT); - } - }; // There are two scenarios that can trigger the SeekBar listener to trigger: // // The first is the user using the TouchPad to adjust the position of the @@ -129,72 +105,9 @@ public void onClick(View view) { // we will simply apply the updated position without suspending regular updates. @Nullable private SeekBar.OnSeekBarChangeListener seekListener = new OnSeekChangeListener(); - @Nullable - private View.OnClickListener rewListener = new OnClickListener() { - @Override - public void onClick(View v) { - if (videoMediaPlayer == null) { - return; - } - int pos = videoMediaPlayer.getCurrentPosition(); - pos -= rewindDuration; // milliseconds - videoMediaPlayer.seekTo(pos); - setProgress(); - - show(DEFAULT_TIMEOUT); - } - }; @Nullable - private View.OnClickListener ffwdListener = new OnClickListener() { - @Override - public void onClick(View v) { - if (videoMediaPlayer == null) { - return; - } - - int pos = videoMediaPlayer.getCurrentPosition(); - pos += fastForwardDuration; // milliseconds - videoMediaPlayer.seekTo(pos); - setProgress(); - - show(DEFAULT_TIMEOUT); - } - }; - @Nullable - private View.OnClickListener playbackSpeedListener = new OnClickListener() { - @Override - public void onClick(View v) { - // Inflate the PopupMenu -// popupMenu.getMenuInflater() -// .inflate(R.menu.playback_speed_popup_menu, popupMenu.getMenu()); - - popupMenu.setOnSpeedSelectedListener(new OnPlaybackSpeedSelectedListener() { - @Override - public void onSpeedSelected(float speed, String text) { - // Update the Playback Speed Drawable according to the clicked menu item - buttonManager.updatePlaybackSpeedText(text); - // Change the Playback Speed of the VideoMediaPlayer - videoMediaPlayer.changePlaybackSpeed(speed); - // Hide the VideoControllerView - hide(); - } - }); - - popupMenu.setOnDismissListener(new PopupMenu.OnDismissListener() { - @Override - public void onDismiss(PopupMenu menu) { - show(); - } - }); - - // Show the PopupMenu - popupMenu.show(); - - // Show the VideoControllerView and until hide is called - show(0); - } - }; + private MediaControllerListener mediaControllerListener; private ButtonManager buttonManager; private int progressBarColor = Color.WHITE; @@ -206,7 +119,7 @@ public VideoControllerView(Context context) { super(context); LayoutInflater layoutInflater = LayoutInflater.from(context); layoutInflater.inflate(R.layout.video_controller, this, true); - initControllerView(); + init(); } public VideoControllerView(Context context, AttributeSet attrs) { @@ -214,63 +127,25 @@ public VideoControllerView(Context context, AttributeSet attrs) { LayoutInflater layoutInflater = LayoutInflater.from(getContext()); layoutInflater.inflate(R.layout.video_controller, this, true); - initControllerView(); + init(); setupXmlAttributes(attrs); } - private void setupXmlAttributes(AttributeSet attrs) { - TypedArray typedArray = getContext().obtainStyledAttributes(attrs, - R.styleable.VideoControllerView, 0, 0); - buttonManager.setupDrawables(typedArray); - setupProgressBar(typedArray); - // Recycle the TypedArray - typedArray.recycle(); - } - - private void setupProgressBar(TypedArray a) { - int color = a.getColor(R.styleable.VideoControllerView_progress_color, 0); - if (color != 0) { - // Set the default color - progressBarColor = color; - } - progress.getProgressDrawable().setColorFilter(progressBarColor, PorterDuff.Mode.SRC_IN); - progress.getThumb().setColorFilter(progressBarColor, PorterDuff.Mode.SRC_IN); - } - - private void initControllerView() { + private void init() { if (!isInEditMode()) { setVisibility(INVISIBLE); } - startPauseButton = findViewById(R.id.start_pause_media_button); - if (startPauseButton != null) { - startPauseButton.requestFocus(); - startPauseButton.setOnClickListener(pauseListener); - } - - fullscreenButton = findViewById(R.id.fullscreen_media_button); - if (fullscreenButton != null) { - fullscreenButton.requestFocus(); - fullscreenButton.setOnClickListener(fullscreenListener); - } - - ffwdButton = findViewById(R.id.forward_media_button); - if (ffwdButton != null) { - ffwdButton.setOnClickListener(ffwdListener); - } - - rewButton = findViewById(R.id.rewind_media_button); - if (rewButton != null) { - rewButton.setOnClickListener(rewListener); - } - - playbackSpeedButton = findViewById(R.id.playback_speed_button); - if (playbackSpeedButton != null) { - playbackSpeedButton.setOnClickListener(playbackSpeedListener); - } + buttonManager = new ButtonManager( + getContext(), + (ImageButton) findViewById(R.id.start_pause_media_button), + (ImageButton) findViewById(R.id.forward_media_button), + (ImageButton) findViewById(R.id.rewind_media_button), + (ImageButton) findViewById(R.id.fullscreen_media_button), + (TextView) findViewById(R.id.playback_speed_button) + ); - buttonManager = new ButtonManager(getContext(), startPauseButton, ffwdButton, rewButton, - fullscreenButton, playbackSpeedButton); + setupButtonListeners(); progress = findViewById(R.id.progress_seek_bar); if (progress != null) { @@ -284,6 +159,127 @@ private void initControllerView() { currentTime = findViewById(R.id.time_current); } + private void setupButtonListeners() { + buttonManager.setStartPauseButtonClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (videoMediaPlayer != null && mediaControllerListener != null) { + if (videoMediaPlayer.isPlaying()) { + mediaControllerListener.onPauseClicked(); + } else { + mediaControllerListener.onPlayClicked(); + } + } + + doPauseResume(); + show(DEFAULT_TIMEOUT); + } + }); + + buttonManager.setFullscreenButtonClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + if (mediaControllerListener != null) { + mediaControllerListener.onFullscreenClicked(); + } + + view.setTag(VIEW_TAG_CLICKED); + doToggleFullscreen(); + show(DEFAULT_TIMEOUT); + } + }); + + buttonManager.setFfwdButtonOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (videoMediaPlayer == null) { + return; + } + + if (mediaControllerListener != null) { + mediaControllerListener.onFastForwardClicked(); + } + + int pos = videoMediaPlayer.getCurrentPosition(); + pos += fastForwardDuration; // milliseconds + videoMediaPlayer.seekTo(pos); + setProgress(); + + show(DEFAULT_TIMEOUT); + } + }); + + buttonManager.setRewButtonOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (videoMediaPlayer == null) { + return; + } + + if (mediaControllerListener != null) { + mediaControllerListener.onRewindClicked(); + } + + int pos = videoMediaPlayer.getCurrentPosition(); + pos -= rewindDuration; // milliseconds + videoMediaPlayer.seekTo(pos); + setProgress(); + + show(DEFAULT_TIMEOUT); + } + }); + + buttonManager.setPlaybackSpeedPopupMenuListener( + new PlaybackSpeedPopupMenuListener() { + @Override + public void onSpeedSelected(float speed, String text) { + // Update the Playback Speed Drawable according to the clicked menu item + buttonManager.updatePlaybackSpeedText(text); + // Change the Playback Speed of the VideoMediaPlayer + if (videoMediaPlayer != null) { + videoMediaPlayer.changePlaybackSpeed(speed); + } + // Hide the VideoControllerView + hide(); + } + + @Override + public void onPopupMenuDismissed() { + show(); + } + + @Override + public void onPopupMenuShown() { + // Show the VideoControllerView and until hide is called + show(0); + } + } + ); + } + + private void setupXmlAttributes(AttributeSet attrs) { + TypedArray typedArray = getContext().obtainStyledAttributes( + attrs, + R.styleable.VideoControllerView, + 0, + 0 + ); + buttonManager.setupDrawables(typedArray); + setupProgressBar(typedArray); + // Recycle the TypedArray + typedArray.recycle(); + } + + private void setupProgressBar(TypedArray a) { + int color = a.getColor(R.styleable.VideoControllerView_progress_color, 0); + if (color != 0) { + // Set the default color + progressBarColor = color; + } + progress.getProgressDrawable().setColorFilter(progressBarColor, PorterDuff.Mode.SRC_IN); + progress.getThumb().setColorFilter(progressBarColor, PorterDuff.Mode.SRC_IN); + } + /** * Show the controller on screen. It will go away * automatically after 3 seconds of inactivity. @@ -300,30 +296,7 @@ private void setupButtonsVisibility() { return; } - try { - if (startPauseButton != null && !videoMediaPlayer.canPause()) { - startPauseButton.setEnabled(false); - startPauseButton.setVisibility(INVISIBLE); - } - if (rewButton != null && !videoMediaPlayer.showSeekBackwardButton()) { - rewButton.setEnabled(false); - rewButton.setVisibility(INVISIBLE); - } - if (ffwdButton != null && !videoMediaPlayer.showSeekForwardButton()) { - ffwdButton.setEnabled(false); - ffwdButton.setVisibility(INVISIBLE); - } - if (playbackSpeedButton != null && !videoMediaPlayer.showPlaybackSpeedButton()) { - playbackSpeedButton.setEnabled(false); - playbackSpeedButton.setVisibility(INVISIBLE); - } - } catch (IncompatibleClassChangeError ex) { - // We were given an old version of the interface, that doesn't have - // the canPause/canSeekXYZ methods. This is OK, it just means we - // assume the media can be paused and seeked, and so we don't disable - // the buttons. - ex.printStackTrace(); - } + buttonManager.setupButtonsVisibility(); } /** @@ -335,10 +308,8 @@ private void setupButtonsVisibility() { */ private void show(int timeout) { if (!isShowing()) { + buttonManager.requestStartPauseButtonFocus(); setProgress(); - if (startPauseButton != null) { - startPauseButton.requestFocus(); - } setupButtonsVisibility(); setVisibility(VISIBLE); } @@ -407,6 +378,7 @@ private int setProgress() { long pos = Constants.ONE_MILLISECOND * position / duration; progress.setProgress((int) pos); } + int percent = videoMediaPlayer.getBufferPercentage(); progress.setSecondaryProgress(percent * 10); } @@ -448,34 +420,20 @@ private void doToggleFullscreen() { @Override public void setEnabled(boolean enabled) { - if (startPauseButton != null) { - startPauseButton.setEnabled(enabled); - } - if (ffwdButton != null) { - ffwdButton.setEnabled(enabled); - } - if (rewButton != null) { - rewButton.setEnabled(enabled); - } - if (playbackSpeedButton != null) { - playbackSpeedButton.setEnabled(enabled); - } + buttonManager.setButtonsEnabled(enabled); if (progress != null) { progress.setEnabled(enabled); } + setupButtonsVisibility(); super.setEnabled(enabled); } public void onDetach() { - ffwdListener = null; - fullscreenListener = null; - pauseListener = null; - rewListener = null; seekListener = null; - playbackSpeedListener = null; handler = null; videoMediaPlayer = null; + mediaControllerListener = null; } public void setEnterFullscreenDrawable(Drawable enterFullscreenDrawable) { @@ -515,11 +473,17 @@ public void setRewindDrawable(Drawable rewindDrawable) { } public void setPlaybackSpeedOptions(PlaybackSpeedOptions playbackSpeedOptions) { - popupMenu.setPlaybackSpeedOptions(playbackSpeedOptions); + buttonManager.setPlaybackSpeedOptions(playbackSpeedOptions); + } + + public void setOnMediaControllerListener(MediaControllerListener mediaControllerListener) { + this.mediaControllerListener = mediaControllerListener; } - public void init(final OrientationManager orientationManager, VideoMediaPlayer videoMediaPlayer, + public void init(final OrientationManager orientationManager, + VideoMediaPlayer videoMediaPlayer, AttributeSet attrs) { + setupXmlAttributes(attrs); this.videoMediaPlayer = videoMediaPlayer; @@ -530,20 +494,17 @@ public void init(final OrientationManager orientationManager, VideoMediaPlayer v buttonManager.updateFastForwardDrawable(); buttonManager.updateRewindDrawable(); - // Initialize the PopupMenu - popupMenu = new PlaybackSpeedPopupMenu(getContext(), playbackSpeedButton); - getViewTreeObserver().addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() { @Override public void onWindowFocusChanged(boolean hasFocus) { if (orientationManager.isLandscape()) { ((Activity) getContext()).getWindow().getDecorView() - .setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + .setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_FULLSCREEN | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN ); } } @@ -557,7 +518,7 @@ public void hideProgress() { } public void hideFullscreenButton() { - fullscreenButton.setVisibility(View.GONE); + buttonManager.hideFullscreenButton(); } private static class MessageHandler extends Handler { @@ -621,6 +582,12 @@ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (currentTime != null) { currentTime.setText(stringForTime((int) newPosition)); } + + if (mediaControllerListener != null) { + mediaControllerListener.onSeekBarProgressChanged(newPosition); + } + + videoMediaPlayer.hideThumbnail(); } @Override diff --git a/library/src/main/java/bg/devlabs/fullscreenvideoview/VideoMediaPlayer.java b/library/src/main/java/bg/devlabs/fullscreenvideoview/VideoMediaPlayer.java index 95af20a..07a5986 100644 --- a/library/src/main/java/bg/devlabs/fullscreenvideoview/VideoMediaPlayer.java +++ b/library/src/main/java/bg/devlabs/fullscreenvideoview/VideoMediaPlayer.java @@ -71,9 +71,13 @@ public void onPauseResume() { pause(); } else { start(); - if (fullscreenVideoView != null) { - fullscreenVideoView.hideThumbnail(); - } + hideThumbnail(); + } + } + + public void hideThumbnail() { + if (fullscreenVideoView != null) { + fullscreenVideoView.hideThumbnail(); } } diff --git a/library/src/main/java/bg/devlabs/fullscreenvideoview/listener/mediacontroller/MediaControllerListener.java b/library/src/main/java/bg/devlabs/fullscreenvideoview/listener/mediacontroller/MediaControllerListener.java new file mode 100644 index 0000000..1a576e0 --- /dev/null +++ b/library/src/main/java/bg/devlabs/fullscreenvideoview/listener/mediacontroller/MediaControllerListener.java @@ -0,0 +1,59 @@ +/* + * Copyright 2017 Dev Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bg.devlabs.fullscreenvideoview.listener.mediacontroller; + +/** + * Created by Slavi Petrov on 14.08.2019 + * Dev Labs + * slavi@devlabs.bg + * + * Listener for media controller events. + */ +public interface MediaControllerListener { + + /** + * The play button has been clicked. + */ + void onPlayClicked(); + + /** + * The pause button has been clicked. + */ + void onPauseClicked(); + + /** + * The rewind button has been clicked. + */ + void onRewindClicked(); + + /** + * The fast forward button has been clicked. + */ + void onFastForwardClicked(); + + /** + * The fullscreen button is clicked. + */ + void onFullscreenClicked(); + + /** + * The SeekBar progress is changed from user interaction. + * + * @param progressMs the progress in milliseconds + */ + void onSeekBarProgressChanged(long progressMs); +} diff --git a/library/src/main/java/bg/devlabs/fullscreenvideoview/listener/mediacontroller/MediaControllerListenerAdapter.java b/library/src/main/java/bg/devlabs/fullscreenvideoview/listener/mediacontroller/MediaControllerListenerAdapter.java new file mode 100644 index 0000000..8721e00 --- /dev/null +++ b/library/src/main/java/bg/devlabs/fullscreenvideoview/listener/mediacontroller/MediaControllerListenerAdapter.java @@ -0,0 +1,38 @@ +package bg.devlabs.fullscreenvideoview.listener.mediacontroller; + +/** + * Created by Slavi Petrov on 14.08.2019 + * Dev Labs + * slavi@devlabs.bg + * + * This adapter class provides empty implementations of the methods + * from [{@link MediaControllerListener}]. Any custom listener that cares only about a subset of + * the methods of this listener can simply subclass this adapter class instead of implementing + * the interface directly. + */ +@SuppressWarnings("unused") +public class MediaControllerListenerAdapter implements MediaControllerListener { + @Override + public void onPlayClicked() { + } + + @Override + public void onPauseClicked() { + } + + @Override + public void onRewindClicked() { + } + + @Override + public void onFastForwardClicked() { + } + + @Override + public void onFullscreenClicked() { + } + + @Override + public void onSeekBarProgressChanged(long progressMs) { + } +} diff --git a/library/src/main/java/bg/devlabs/fullscreenvideoview/playbackspeed/PlaybackSpeedPopupMenu.java b/library/src/main/java/bg/devlabs/fullscreenvideoview/playbackspeed/PlaybackSpeedPopupMenu.java index 9faf5b6..b9bbd19 100644 --- a/library/src/main/java/bg/devlabs/fullscreenvideoview/playbackspeed/PlaybackSpeedPopupMenu.java +++ b/library/src/main/java/bg/devlabs/fullscreenvideoview/playbackspeed/PlaybackSpeedPopupMenu.java @@ -32,7 +32,9 @@ */ public class PlaybackSpeedPopupMenu extends android.support.v7.widget.PopupMenu { - private ArrayList values = new ArrayList<>(Arrays.asList(0.25f, 0.5f, 0.75f, 1f, 1.25f, 1.5f, 2f)); + private ArrayList values = new ArrayList<>( + Arrays.asList(0.25f, 0.5f, 0.75f, 1f, 1.25f, 1.5f, 2f) + ); public PlaybackSpeedPopupMenu(Context context, View anchor) { super(context, anchor); diff --git a/library/src/main/java/bg/devlabs/fullscreenvideoview/playbackspeed/PlaybackSpeedPopupMenuListener.java b/library/src/main/java/bg/devlabs/fullscreenvideoview/playbackspeed/PlaybackSpeedPopupMenuListener.java new file mode 100644 index 0000000..5e62628 --- /dev/null +++ b/library/src/main/java/bg/devlabs/fullscreenvideoview/playbackspeed/PlaybackSpeedPopupMenuListener.java @@ -0,0 +1,43 @@ +/* + * Copyright 2017 Dev Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bg.devlabs.fullscreenvideoview.playbackspeed; + +/** + * Created by Slavi Petrov on 14.08.2019 + * Dev Labs + * slavi@devlabs.bg + */ +public interface PlaybackSpeedPopupMenuListener { + + /** + * A playback speed is selected. + * + * @param speed the value of the speed + * @param text the speed value converted to string + */ + void onSpeedSelected(float speed, String text); + + /** + * The PopupMenu is dismissed. + */ + void onPopupMenuDismissed(); + + /** + * The PopupMenu is shown. + */ + void onPopupMenuShown(); +}