diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 61a9130..fb7f4a8 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 3eac69b..a750660 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -43,7 +43,7 @@ - + diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..797acea --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3b78ec8..8b30a6e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ android { defaultConfig { applicationId "com.potyvideo.andexoplayer" - minSdkVersion 16 + minSdkVersion 19 targetSdkVersion 29 versionCode 1 versionName "1.0" diff --git a/app/src/main/java/com/potyvideo/andexoplayer/MainActivityKotlin.kt b/app/src/main/java/com/potyvideo/andexoplayer/MainActivityKotlin.kt index 26bb13a..3c05602 100644 --- a/app/src/main/java/com/potyvideo/andexoplayer/MainActivityKotlin.kt +++ b/app/src/main/java/com/potyvideo/andexoplayer/MainActivityKotlin.kt @@ -24,7 +24,7 @@ class MainActivityKotlin : AppCompatActivity(), AndExoPlayerListener, View.OnCli andExoPlayerView = findViewById(R.id.andExoPlayerView) - andExoPlayerView.setResizeMode(EnumResizeMode.FIT) // sync with attrs + andExoPlayerView.setResizeMode(EnumResizeMode.ZOOM) // sync with attrs andExoPlayerView.setAndExoPlayerListener(this) findViewById(R.id.local).setOnClickListener(this) @@ -33,6 +33,9 @@ class MainActivityKotlin : AppCompatActivity(), AndExoPlayerListener, View.OnCli findViewById(R.id.stream_dash).setOnClickListener(this) findViewById(R.id.stream_mkv).setOnClickListener(this) + // starter stream + loadMP4Stream(PublicValues.TEST_URL_MP4_V3) + } override fun onExoPlayerError(errorMessage: String?) { @@ -44,7 +47,7 @@ class MainActivityKotlin : AppCompatActivity(), AndExoPlayerListener, View.OnCli selectLocaleVideo() } R.id.stream_mp4 -> { - loadMP4Stream(PublicValues.TEST_URL_MP4) + loadMP4Stream(PublicValues.TEST_URL_MP4_V3) } R.id.stream_hls -> { loadHLSStream(PublicValues.TEST_URL_HLS) @@ -85,7 +88,10 @@ class MainActivityKotlin : AppCompatActivity(), AndExoPlayerListener, View.OnCli intent.type = "video/*" intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true) intent.action = Intent.ACTION_GET_CONTENT - startActivityForResult(Intent.createChooser(intent, "Select Video"), PublicValues.request_code_select_video) + startActivityForResult( + Intent.createChooser(intent, "Select Video"), + PublicValues.request_code_select_video + ) } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 582c409..8b515ee 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -10,11 +10,11 @@ android:layout_width="match_parent" android:layout_height="wrap_content" app:andexo_aspect_ratio="aspect_16_9" - app:andexo_full_screen="true" app:andexo_loop="finite" app:andexo_play_when_ready="true" app:andexo_resize_mode="Fit" - app:andexo_show_controller="true" /> + app:andexo_show_controller="true" + app:andexo_show_full_screen="true" /> + android:layout_weight="1" + app:andexo_show_controller="true" + app:andexo_show_full_screen="true" /> { + enterFullScreen.visibility = GONE + exitFullScreen.visibility = VISIBLE + } + EnumScreenMode.MINIMISE -> { + enterFullScreen.visibility = VISIBLE + exitFullScreen.visibility = GONE + } + else -> { + enterFullScreen.visibility = VISIBLE + exitFullScreen.visibility = GONE + } + } + } + + protected fun showSystemUI() { + playerView.systemUiVisibility = (SYSTEM_UI_FLAG_LOW_PROFILE + or SYSTEM_UI_FLAG_IMMERSIVE + or SYSTEM_UI_FLAG_FULLSCREEN + or SYSTEM_UI_FLAG_LAYOUT_STABLE + or SYSTEM_UI_FLAG_IMMERSIVE_STICKY + or SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + or SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + or SYSTEM_UI_FLAG_HIDE_NAVIGATION) + } + + protected fun hideSystemUI() { + playerView.systemUiVisibility = (SYSTEM_UI_FLAG_LOW_PROFILE + or SYSTEM_UI_FLAG_LAYOUT_STABLE) + } + } diff --git a/library/src/main/java/com/potyvideo/library/AndExoPlayerView.kt b/library/src/main/java/com/potyvideo/library/AndExoPlayerView.kt index 957d0a7..0d16039 100644 --- a/library/src/main/java/com/potyvideo/library/AndExoPlayerView.kt +++ b/library/src/main/java/com/potyvideo/library/AndExoPlayerView.kt @@ -1,6 +1,10 @@ package com.potyvideo.library +import android.app.Activity import android.content.Context +import android.content.ContextWrapper +import android.content.pm.ActivityInfo +import android.content.res.Configuration import android.content.res.TypedArray import android.util.AttributeSet import android.view.View @@ -11,19 +15,18 @@ import com.google.android.exoplayer2.source.TrackGroupArray import com.google.android.exoplayer2.trackselection.TrackSelectionArray import com.google.android.exoplayer2.ui.AspectRatioFrameLayout import com.google.android.exoplayer2.util.MimeTypes -import com.potyvideo.library.globalEnums.EnumAspectRatio -import com.potyvideo.library.globalEnums.EnumMute -import com.potyvideo.library.globalEnums.EnumRepeatMode -import com.potyvideo.library.globalEnums.EnumResizeMode +import com.potyvideo.library.globalEnums.* import com.potyvideo.library.globalInterfaces.AndExoPlayerListener import com.potyvideo.library.utils.DoubleClick import com.potyvideo.library.utils.DoubleClickListener import com.potyvideo.library.utils.PublicFunctions import com.potyvideo.library.utils.PublicValues + class AndExoPlayerView( - context: Context, - attributeSet: AttributeSet) : AndExoPlayerRoot(context, attributeSet), Player.EventListener { + context: Context, + attributeSet: AttributeSet +) : AndExoPlayerRoot(context, attributeSet), Player.EventListener { private lateinit var currSource: String @@ -33,7 +36,6 @@ class AndExoPlayerView( private var playbackPosition: Long = 0 private var currentWindow: Int = 0 private var currVolume: Float = 0f - private var showControllers: Boolean = true override var customClickListener: DoubleClick get() = DoubleClick(object : DoubleClickListener { @@ -49,6 +51,12 @@ class AndExoPlayerView( unMute.id -> { mutePlayer() } + enterFullScreen.id -> { + setScreenMode(EnumScreenMode.FULLSCREEN) + } + exitFullScreen.id -> { + setScreenMode(EnumScreenMode.MINIMISE) + } } } @@ -74,29 +82,58 @@ class AndExoPlayerView( attributeSet.let { - val typedArray: TypedArray = context.obtainStyledAttributes(it, R.styleable.AndExoPlayerView) + val typedArray: TypedArray = + context.obtainStyledAttributes(it, R.styleable.AndExoPlayerView) if (typedArray.hasValue(R.styleable.AndExoPlayerView_andexo_aspect_ratio)) { - val aspectRatio = typedArray.getInteger(R.styleable.AndExoPlayerView_andexo_aspect_ratio, EnumAspectRatio.ASPECT_16_9.value) + val aspectRatio = typedArray.getInteger( + R.styleable.AndExoPlayerView_andexo_aspect_ratio, + EnumAspectRatio.ASPECT_16_9.value + ) setAspectRatio(EnumAspectRatio[aspectRatio]) } if (typedArray.hasValue(R.styleable.AndExoPlayerView_andexo_resize_mode)) { - val resizeMode: Int = typedArray.getInteger(R.styleable.AndExoPlayerView_andexo_resize_mode, EnumResizeMode.FILL.value) + val resizeMode: Int = typedArray.getInteger( + R.styleable.AndExoPlayerView_andexo_resize_mode, + EnumResizeMode.FILL.value + ) setResizeMode(EnumResizeMode[resizeMode]) } if (typedArray.hasValue(R.styleable.AndExoPlayerView_andexo_play_when_ready)) { - setPlayWhenReady(typedArray.getBoolean(R.styleable.AndExoPlayerView_andexo_play_when_ready, false)) + setPlayWhenReady( + typedArray.getBoolean( + R.styleable.AndExoPlayerView_andexo_play_when_ready, + false + ) + ) } if (typedArray.hasValue(R.styleable.AndExoPlayerView_andexo_mute)) { - val muteValue = typedArray.getInteger(R.styleable.AndExoPlayerView_andexo_mute, EnumMute.UNMUTE.value) + val muteValue = typedArray.getInteger( + R.styleable.AndExoPlayerView_andexo_mute, + EnumMute.UNMUTE.value + ) setMute(EnumMute[muteValue]) } if (typedArray.hasValue(R.styleable.AndExoPlayerView_andexo_show_controller)) { + setShowControllers( + typedArray.getBoolean( + R.styleable.AndExoPlayerView_andexo_show_controller, + true + ) + ) + } + if (typedArray.hasValue(R.styleable.AndExoPlayerView_andexo_show_full_screen)) { + setShowFullScreenButton( + typedArray.getBoolean( + R.styleable.AndExoPlayerView_andexo_show_full_screen, + true + ) + ) } typedArray.recycle() @@ -106,7 +143,10 @@ class AndExoPlayerView( override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters) { } - override fun onTracksChanged(trackGroups: TrackGroupArray, trackSelections: TrackSelectionArray) { + override fun onTracksChanged( + trackGroups: TrackGroupArray, + trackSelections: TrackSelectionArray + ) { } override fun onPlayerError(error: ExoPlaybackException) { @@ -161,54 +201,64 @@ class AndExoPlayerView( player.prepare() } - private fun buildMediaItem(source: String): MediaItem { + private fun buildMediaItem(source: String, extraHeaders: HashMap): MediaItem { return when (PublicFunctions.getMimeType(source)) { - PublicValues.KEY_MP4 -> buildMediaItemMP4(source) - PublicValues.KEY_M3U8 -> buildMediaHLS(source) - PublicValues.KEY_MP3 -> buildMediaItemMP4(source) + PublicValues.KEY_MP4 -> buildMediaItemMP4(source, extraHeaders) + PublicValues.KEY_M3U8 -> buildMediaHLS(source, extraHeaders) + PublicValues.KEY_MP3 -> buildMediaItemMP4(source, extraHeaders) - else -> buildMediaGlobal(source) + else -> buildMediaGlobal(source, extraHeaders) } } - private fun buildMediaItemMP4(source: String): MediaItem { + private fun buildMediaItemMP4( + source: String, + extraHeaders: HashMap + ): MediaItem { return MediaItem.Builder() - .setUri(source) - .setMimeType(MimeTypes.APPLICATION_MP4) - .build() + .setUri(source) + .setMimeType(MimeTypes.APPLICATION_MP4) + .setDrmLicenseRequestHeaders(extraHeaders) + .build() } - private fun buildMediaHLS(source: String): MediaItem { + private fun buildMediaHLS(source: String, extraHeaders: HashMap): MediaItem { return MediaItem.Builder() - .setUri(source) - .setMimeType(MimeTypes.APPLICATION_M3U8) - .build() + .setUri(source) + .setMimeType(MimeTypes.APPLICATION_M3U8) + .setDrmLicenseRequestHeaders(extraHeaders) + .build() } - private fun buildMediaDash(source: String): MediaItem { + private fun buildMediaDash(source: String, extraHeaders: HashMap): MediaItem { return MediaItem.Builder() - .setUri(source) - .setMimeType(MimeTypes.APPLICATION_MPD) - .build() + .setUri(source) + .setMimeType(MimeTypes.APPLICATION_MPD) + .setDrmLicenseRequestHeaders(extraHeaders) + .build() } - private fun buildMediaGlobal(source: String): MediaItem { + private fun buildMediaGlobal(source: String, extraHeaders: HashMap): MediaItem { return MediaItem.Builder() - .setUri(source) - .build() + .setUri(source) + .setDrmLicenseRequestHeaders(extraHeaders) + .build() } fun setAndExoPlayerListener(andExoPlayerListener: AndExoPlayerListener) { this.andExoPlayerListener = andExoPlayerListener } - fun setSource(source: String) { + fun setSource( + source: String, + extraHeaders: HashMap = hashMapOf() + ) { currSource = source - val mediaItem = buildMediaItem(source) + val mediaItem = buildMediaItem(source, extraHeaders) playerView.player = player player.playWhenReady = true @@ -288,19 +338,28 @@ class AndExoPlayerView( this.currAspectRatio = aspectRatio val value = PublicFunctions.getScreenWidth() when (aspectRatio) { - EnumAspectRatio.ASPECT_1_1 -> playerView.layoutParams = FrameLayout.LayoutParams(value, value) - EnumAspectRatio.ASPECT_4_3 -> playerView.layoutParams = FrameLayout.LayoutParams(value, 3 * value / 4) - EnumAspectRatio.ASPECT_16_9 -> playerView.layoutParams = FrameLayout.LayoutParams(value, 9 * value / 16) - EnumAspectRatio.ASPECT_MATCH -> playerView.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + EnumAspectRatio.ASPECT_1_1 -> playerView.layoutParams = + FrameLayout.LayoutParams(value, value) + EnumAspectRatio.ASPECT_4_3 -> playerView.layoutParams = + FrameLayout.LayoutParams(value, 3 * value / 4) + EnumAspectRatio.ASPECT_16_9 -> playerView.layoutParams = + FrameLayout.LayoutParams(value, 9 * value / 16) + EnumAspectRatio.ASPECT_MATCH -> playerView.layoutParams = FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) EnumAspectRatio.ASPECT_MP3 -> { playerView.controllerShowTimeoutMs = 0 playerView.controllerHideOnTouch = false - val mp3Height = context.resources.getDimensionPixelSize(R.dimen.player_controller_base_height) - playerView.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mp3Height) + val mp3Height = + context.resources.getDimensionPixelSize(R.dimen.player_controller_base_height) + playerView.layoutParams = + FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mp3Height) } EnumAspectRatio.UNDEFINE -> { val baseHeight = resources.getDimension(R.dimen.player_base_height).toInt() - playerView.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, baseHeight) + playerView.layoutParams = + FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, baseHeight) } } } @@ -334,4 +393,60 @@ class AndExoPlayerView( player.playbackState } + fun setScreenMode(screenMode: EnumScreenMode = EnumScreenMode.MINIMISE) { + + when (screenMode) { + EnumScreenMode.FULLSCREEN -> { + getActivity()?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; + } + EnumScreenMode.MINIMISE -> { + getActivity()?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; + } + else -> { + getActivity()?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; + } + } + + currScreenMode = screenMode + setShowScreenModeButton(currScreenMode) + } + + fun getActivity(): Activity? { + var context = context + while (context is ContextWrapper) { + if (context is Activity) { + return context + } + context = context.baseContext + } + return null + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + releasePlayer() + } + + override fun onConfigurationChanged(newConfig: Configuration?) { + super.onConfigurationChanged(newConfig) + // Checking the orientation of the screen + // Checking the orientation of the screen + if (newConfig!!.orientation == Configuration.ORIENTATION_LANDSCAPE) { + // First Hide other objects (list-view or recyclerview), better hide them using Gone. + hideSystemUI() + val params = playerView.layoutParams as FrameLayout.LayoutParams + params.width = ViewGroup.LayoutParams.MATCH_PARENT + params.height = ViewGroup.LayoutParams.MATCH_PARENT + playerView.layoutParams = params + } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { + // un hide your objects here. + showSystemUI() + setAspectRatio(currAspectRatio) + } + } + } \ No newline at end of file diff --git a/library/src/main/java/com/potyvideo/library/globalEnums/EnumScreenMode.kt b/library/src/main/java/com/potyvideo/library/globalEnums/EnumScreenMode.kt new file mode 100644 index 0000000..a9b336e --- /dev/null +++ b/library/src/main/java/com/potyvideo/library/globalEnums/EnumScreenMode.kt @@ -0,0 +1,37 @@ +package com.potyvideo.library.globalEnums + +enum class EnumScreenMode(var valueStr: String, val value: Int) { + + UNDEFINE("UNDEFINE", -1), + FULLSCREEN("fullscreen", 1), + MINIMISE("minimise", 2); + + companion object { + + operator fun get(value: String): EnumScreenMode { + if (value == null) { + return UNDEFINE + } + val `arr$` = values() + for (`val` in `arr$`) { + if (`val`.valueStr.equals(value.trim { it <= ' ' }, ignoreCase = true)) { + return `val` + } + } + return UNDEFINE + } + + operator fun get(value: Int): EnumScreenMode { + if (value == null) { + return UNDEFINE + } + val `arr$` = values() + for (`val` in `arr$`) { + if (`val`.value === value) { + return `val` + } + } + return UNDEFINE + } + } +} \ No newline at end of file diff --git a/library/src/main/res/layout/video_player_exo_controllers_kotlin.xml b/library/src/main/res/layout/video_player_exo_controllers_kotlin.xml index ebab84f..8e84acf 100644 --- a/library/src/main/res/layout/video_player_exo_controllers_kotlin.xml +++ b/library/src/main/res/layout/video_player_exo_controllers_kotlin.xml @@ -132,10 +132,8 @@ android:id="@+id/container_audio" android:layout_width="40dp" android:layout_height="40dp" - android:layout_alignParentStart="true" - android:layout_alignParentLeft="true" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toStartOf="@id/container_setting" + app:layout_constraintEnd_toStartOf="@id/container_fullscreen" app:layout_constraintTop_toTopOf="parent"> + + + + + + + + + diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml index dc73b3c..c26d48a 100644 --- a/library/src/main/res/values/attrs.xml +++ b/library/src/main/res/values/attrs.xml @@ -6,7 +6,7 @@ - +