started to use ExoPlayer for jellybean+
This commit is contained in:
parent
d42165c53b
commit
4dc08599fa
24
build.gradle
24
build.gradle
|
@ -31,16 +31,20 @@ allprojects {
|
|||
|
||||
subprojects {
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.0.6'
|
||||
ext.android_support_lib_version = '25.2.0'
|
||||
ext.mariotaku_commons_library_version = '0.9.11'
|
||||
ext.mariotaku_restfu_version = '0.9.35'
|
||||
ext.mariotaku_object_cursor_version = '0.9.13'
|
||||
ext.play_services_version = '10.2.0'
|
||||
ext.crashlyrics_version = '2.6.6'
|
||||
ext.fabric_plugin_version = '1.22.0'
|
||||
ext.dropbox_core_sdk_version = '2.1.2'
|
||||
ext.google_api_drive_version = 'v3-rev55-1.22.0'
|
||||
ext {
|
||||
kotlin_version = '1.0.6'
|
||||
android_support_lib_version = '25.2.0'
|
||||
mariotaku_commons_library_version = '0.9.11'
|
||||
mariotaku_restfu_version = '0.9.35'
|
||||
mariotaku_object_cursor_version = '0.9.13'
|
||||
play_services_version = '10.2.0'
|
||||
crashlyrics_version = '2.6.6'
|
||||
fabric_plugin_version = '1.22.0'
|
||||
dropbox_core_sdk_version = '2.1.2'
|
||||
google_api_drive_version = 'v3-rev55-1.22.0'
|
||||
exoplayer_version = 'r2.2.0'
|
||||
toro_version = '2.1.0'
|
||||
}
|
||||
|
||||
}
|
||||
afterEvaluate { project ->
|
||||
|
|
|
@ -168,6 +168,8 @@ dependencies {
|
|||
compile 'org.attoparser:attoparser:2.0.1.RELEASE'
|
||||
compile 'com.getkeepsafe.taptargetview:taptargetview:1.6.0'
|
||||
compile 'net.ypresto.androidtranscoder:android-transcoder:0.2.0'
|
||||
compile "com.google.android.exoplayer:exoplayer:$exoplayer_version"
|
||||
|
||||
compile 'com.github.mariotaku.MediaViewerLibrary:base:0.9.17'
|
||||
compile 'com.github.mariotaku.MediaViewerLibrary:subsample-image-view:0.9.17'
|
||||
compile 'com.github.mariotaku:SQLiteQB:0.9.10'
|
||||
|
@ -180,6 +182,7 @@ dependencies {
|
|||
compile "com.github.mariotaku.CommonsLibrary:text-kotlin:$mariotaku_commons_library_version"
|
||||
compile 'com.github.mariotaku:KPreferences:0.9.5'
|
||||
compile 'com.github.mariotaku:Chameleon:0.9.14'
|
||||
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
compile 'nl.komponents.kovenant:kovenant:3.3.0'
|
||||
compile 'nl.komponents.kovenant:kovenant-android:3.3.0'
|
||||
|
|
|
@ -25,7 +25,6 @@ import org.mariotaku.restfu.http.RestHttpClient;
|
|||
import org.mariotaku.restfu.http.mime.Body;
|
||||
import org.mariotaku.restfu.oauth.OAuthAuthorization;
|
||||
import org.mariotaku.restfu.oauth.OAuthEndpoint;
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.extension.model.CredentialsExtensionsKt;
|
||||
import org.mariotaku.twidere.model.AccountDetails;
|
||||
import org.mariotaku.twidere.model.CacheMetadata;
|
||||
|
@ -44,10 +43,14 @@ import java.io.FileNotFoundException;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_THUMBOR_ADDRESS;
|
||||
import static org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_THUMBOR_ENABLED;
|
||||
import static org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_THUMBOR_SECURITY_KEY;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 16/1/28.
|
||||
*/
|
||||
public class TwidereMediaDownloader implements MediaDownloader, Constants {
|
||||
public class TwidereMediaDownloader implements MediaDownloader {
|
||||
|
||||
private final Context context;
|
||||
private final SharedPreferencesWrapper preferences;
|
||||
|
@ -57,7 +60,7 @@ public class TwidereMediaDownloader implements MediaDownloader, Constants {
|
|||
private Thumbor thumbor;
|
||||
|
||||
public TwidereMediaDownloader(final Context context, SharedPreferencesWrapper preferences,
|
||||
RestHttpClient client) {
|
||||
RestHttpClient client) {
|
||||
this.context = context;
|
||||
this.preferences = preferences;
|
||||
this.client = client;
|
||||
|
@ -116,7 +119,7 @@ public class TwidereMediaDownloader implements MediaDownloader, Constants {
|
|||
}
|
||||
|
||||
protected CacheDownloadLoader.DownloadResult getInternal(@NonNull String url,
|
||||
@Nullable Object extra) throws IOException {
|
||||
@Nullable Object extra) throws IOException {
|
||||
final Uri uri = Uri.parse(url);
|
||||
Authorization auth = null;
|
||||
AccountDetails account = null;
|
||||
|
|
|
@ -49,8 +49,10 @@ import org.mariotaku.twidere.TwidereConstants.*
|
|||
import org.mariotaku.twidere.activity.iface.IControlBarActivity.ControlBarShowHideHelper
|
||||
import org.mariotaku.twidere.activity.iface.IExtendedActivity
|
||||
import org.mariotaku.twidere.annotation.CacheFileType
|
||||
import org.mariotaku.twidere.fragment.*
|
||||
import org.mariotaku.twidere.fragment.PermissionRequestDialog
|
||||
import org.mariotaku.twidere.fragment.ProgressDialogFragment
|
||||
import org.mariotaku.twidere.fragment.iface.IBaseFragment
|
||||
import org.mariotaku.twidere.fragment.media.*
|
||||
import org.mariotaku.twidere.model.ParcelableMedia
|
||||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.provider.CacheProvider
|
||||
|
@ -314,11 +316,18 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
|
|||
args.putBoolean(VideoPageFragment.EXTRA_LOOP, true)
|
||||
args.putBoolean(VideoPageFragment.EXTRA_DISABLE_CONTROL, true)
|
||||
args.putBoolean(VideoPageFragment.EXTRA_DEFAULT_MUTE, true)
|
||||
return Fragment.instantiate(this, VideoPageFragment::class.java.name, args) as MediaViewerFragment
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
|
||||
return Fragment.instantiate(this, VideoPageFragment::class.java.name, args) as MediaViewerFragment
|
||||
} else {
|
||||
return Fragment.instantiate(this, ExoPlayerPageFragment::class.java.name, args) as MediaViewerFragment
|
||||
}
|
||||
}
|
||||
ParcelableMedia.Type.VIDEO -> {
|
||||
return Fragment.instantiate(this,
|
||||
VideoPageFragment::class.java.name, args) as MediaViewerFragment
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
|
||||
return Fragment.instantiate(this, VideoPageFragment::class.java.name, args) as MediaViewerFragment
|
||||
} else {
|
||||
return Fragment.instantiate(this, ExoPlayerPageFragment::class.java.name, args) as MediaViewerFragment
|
||||
}
|
||||
}
|
||||
ParcelableMedia.Type.EXTERNAL_PLAYER -> {
|
||||
return Fragment.instantiate(this, ExternalBrowserPageFragment::class.java.name, args) as MediaViewerFragment
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment.media
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.media.AudioManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.google.android.exoplayer2.DefaultLoadControl
|
||||
import com.google.android.exoplayer2.ExoPlayerFactory
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource
|
||||
import com.google.android.exoplayer2.trackselection.AdaptiveVideoTrackSelection
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
||||
import com.google.android.exoplayer2.upstream.DataSource
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory
|
||||
import kotlinx.android.synthetic.main.layout_media_viewer_exo_player_view.*
|
||||
import kotlinx.android.synthetic.main.layout_media_viewer_video_overlay.*
|
||||
import org.mariotaku.mediaviewer.library.MediaViewerFragment
|
||||
import org.mariotaku.mediaviewer.library.subsampleimageview.SubsampleImageViewerFragment
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_POSITION
|
||||
import org.mariotaku.twidere.fragment.iface.IBaseFragment
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.EXTRA_PAUSED_BY_USER
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.EXTRA_PLAY_AUDIO
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.isMutedByDefault
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.media
|
||||
import org.mariotaku.twidere.util.UserAgentUtils
|
||||
|
||||
|
||||
/**
|
||||
* Successor of `VideoPageFragment`, backed by `ExoPlayer`
|
||||
* Created by mariotaku on 2017/2/28.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||
class ExoPlayerPageFragment : MediaViewerFragment(), IBaseFragment<ExoPlayerPageFragment> {
|
||||
private lateinit var mediaDataSourceFactory: DataSource.Factory
|
||||
private lateinit var mainHandler: Handler
|
||||
|
||||
private var playAudio: Boolean = false
|
||||
private var pausedByUser: Boolean = false
|
||||
private var positionBackup: Int = -1
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
mediaDataSourceFactory = DefaultHttpDataSourceFactory(UserAgentUtils.getDefaultUserAgentString(context))
|
||||
mainHandler = Handler()
|
||||
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
positionBackup = savedInstanceState.getInt(EXTRA_POSITION)
|
||||
pausedByUser = savedInstanceState.getBoolean(EXTRA_PAUSED_BY_USER)
|
||||
playAudio = savedInstanceState.getBoolean(EXTRA_PLAY_AUDIO)
|
||||
} else {
|
||||
val am = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
// Play audio by default if ringer mode on
|
||||
playAudio = !isMutedByDefault && am.ringerMode == AudioManager.RINGER_MODE_NORMAL
|
||||
}
|
||||
|
||||
volumeButton.setOnClickListener {
|
||||
this.playAudio = !this.playAudio
|
||||
updateVolume()
|
||||
}
|
||||
updateVolume()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
|
||||
initializePlayer()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
|
||||
initializePlayer()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
|
||||
releasePlayer()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
|
||||
releasePlayer()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateMediaView(inflater: LayoutInflater, parent: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
return inflater.inflate(R.layout.layout_media_viewer_exo_player_view, parent, false)
|
||||
}
|
||||
|
||||
override fun fitSystemWindows(insets: Rect) {
|
||||
val lp = videoControl.layoutParams
|
||||
if (lp is ViewGroup.MarginLayoutParams) {
|
||||
lp.bottomMargin = insets.bottom
|
||||
lp.leftMargin = insets.left
|
||||
lp.rightMargin = insets.right
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putInt(EXTRA_POSITION, positionBackup)
|
||||
outState.putBoolean(EXTRA_PAUSED_BY_USER, pausedByUser)
|
||||
outState.putBoolean(EXTRA_PLAY_AUDIO, playAudio)
|
||||
}
|
||||
|
||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
||||
super.onViewStateRestored(savedInstanceState)
|
||||
requestFitSystemWindows()
|
||||
}
|
||||
|
||||
override fun recycleMedia() {
|
||||
}
|
||||
|
||||
override fun executeAfterFragmentResumed(useHandler: Boolean, action: (ExoPlayerPageFragment) -> Unit) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
private fun releasePlayer() {
|
||||
if (playerView.player == null) return
|
||||
playerView.player.release();
|
||||
playerView.player = null
|
||||
}
|
||||
|
||||
private fun initializePlayer() {
|
||||
if (playerView.player != null) return
|
||||
playerView.player = run {
|
||||
val bandwidthMeter = DefaultBandwidthMeter()
|
||||
val videoTrackSelectionFactory = AdaptiveVideoTrackSelection.Factory(bandwidthMeter)
|
||||
val trackSelector = DefaultTrackSelector(videoTrackSelectionFactory)
|
||||
val player = ExoPlayerFactory.newSimpleInstance(context, trackSelector, DefaultLoadControl())
|
||||
player.playWhenReady = true
|
||||
return@run player
|
||||
}
|
||||
|
||||
val uri = getDownloadUri() ?: return
|
||||
val mediaSource = ExtractorMediaSource(uri, mediaDataSourceFactory, DefaultExtractorsFactory(),
|
||||
null, null)
|
||||
playerView.player.prepare(mediaSource)
|
||||
updateVolume()
|
||||
}
|
||||
|
||||
private fun updateVolume() {
|
||||
volumeButton.setImageResource(if (playAudio) R.drawable.ic_action_speaker_max else R.drawable.ic_action_speaker_muted)
|
||||
val player = playerView.player ?: return
|
||||
if (playAudio) {
|
||||
player.volume = 1f
|
||||
} else {
|
||||
player.volume = 0f
|
||||
}
|
||||
}
|
||||
|
||||
fun getDownloadUri(): Uri? {
|
||||
val bestVideoUrlAndType = VideoPageFragment.getBestVideoUrlAndType(media, VideoPageFragment.SUPPORTED_VIDEO_TYPES)
|
||||
if (bestVideoUrlAndType != null && bestVideoUrlAndType.first != null) {
|
||||
return Uri.parse(bestVideoUrlAndType.first)
|
||||
}
|
||||
return arguments.getParcelable<Uri>(SubsampleImageViewerFragment.EXTRA_MEDIA_URI)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,23 @@
|
|||
package org.mariotaku.twidere.fragment
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment.media
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
|
@ -11,6 +30,7 @@ import kotlinx.android.synthetic.main.layout_media_viewer_texture_video_view.*
|
|||
import org.mariotaku.mediaviewer.library.MediaViewerFragment
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.EXTRA_MEDIA
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment
|
||||
import org.mariotaku.twidere.model.ParcelableMedia
|
||||
|
||||
class ExternalBrowserPageFragment : MediaViewerFragment() {
|
|
@ -1,4 +1,23 @@
|
|||
package org.mariotaku.twidere.fragment
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment.media
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
|
@ -1,4 +1,23 @@
|
|||
package org.mariotaku.twidere.fragment
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment.media
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
|
@ -1,4 +1,23 @@
|
|||
package org.mariotaku.twidere.fragment
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment.media
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
|
@ -24,8 +43,10 @@ import com.commonsware.cwac.layouts.AspectLockedFrameLayout.AspectRatioSource
|
|||
import edu.tsinghua.hotmobi.HotMobiLogger
|
||||
import edu.tsinghua.hotmobi.model.MediaDownloadEvent
|
||||
import kotlinx.android.synthetic.main.layout_media_viewer_texture_video_view.*
|
||||
import kotlinx.android.synthetic.main.layout_media_viewer_video_overlay.*
|
||||
import org.mariotaku.mediaviewer.library.CacheDownloadLoader
|
||||
import org.mariotaku.mediaviewer.library.CacheDownloadMediaViewerFragment
|
||||
import org.mariotaku.mediaviewer.library.MediaViewerFragment
|
||||
import org.mariotaku.mediaviewer.library.subsampleimageview.SubsampleImageViewerFragment
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.EXTRA_ACCOUNT_KEY
|
||||
|
@ -44,18 +65,13 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), IBaseFragment<Vide
|
|||
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener,
|
||||
View.OnClickListener, IControlBarActivity.ControlBarOffsetListener {
|
||||
|
||||
private val isLoopEnabled: Boolean get() = arguments.getBoolean(EXTRA_LOOP, false)
|
||||
private val isControlDisabled: Boolean get() = arguments.getBoolean(EXTRA_DISABLE_CONTROL, false)
|
||||
private val isMutedByDefault: Boolean get() = arguments.getBoolean(EXTRA_DEFAULT_MUTE, false)
|
||||
private val media: ParcelableMedia? get() = arguments.getParcelable<ParcelableMedia>(EXTRA_MEDIA)
|
||||
private val accountKey: UserKey get() = arguments.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
|
||||
|
||||
private var mediaPlayer: MediaPlayer? = null
|
||||
private var mediaPlayerError: Int = 0
|
||||
|
||||
private var playAudio: Boolean = false
|
||||
private var pausedByUser: Boolean = false
|
||||
private var positionBackup: Int = -1
|
||||
|
||||
private var videoProgressRunnable: VideoPlayProgressRunnable? = null
|
||||
private var mediaDownloadEvent: MediaDownloadEvent? = null
|
||||
|
||||
|
@ -69,8 +85,6 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), IBaseFragment<Vide
|
|||
handler = Handler(activity.mainLooper)
|
||||
}
|
||||
|
||||
val am = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
|
||||
|
||||
videoProgressRunnable = VideoPlayProgressRunnable(handler, videoViewProgress,
|
||||
durationLabel, positionLabel, videoView)
|
||||
|
@ -80,6 +94,7 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), IBaseFragment<Vide
|
|||
pausedByUser = savedInstanceState.getBoolean(EXTRA_PAUSED_BY_USER)
|
||||
playAudio = savedInstanceState.getBoolean(EXTRA_PLAY_AUDIO)
|
||||
} else {
|
||||
val am = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
// Play audio by default if ringer mode on
|
||||
playAudio = !isMutedByDefault && am.ringerMode == AudioManager.RINGER_MODE_NORMAL
|
||||
}
|
||||
|
@ -159,7 +174,6 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), IBaseFragment<Vide
|
|||
requestFitSystemWindows()
|
||||
}
|
||||
|
||||
|
||||
override fun getDownloadExtra(): Any? {
|
||||
val extra = MediaExtra()
|
||||
extra.isUseThumbor = false
|
||||
|
@ -328,27 +342,6 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), IBaseFragment<Vide
|
|||
// No-op
|
||||
}
|
||||
|
||||
@SuppressLint("SwitchIntDef")
|
||||
private fun getBestVideoUrlAndType(media: ParcelableMedia?, supportedTypes: Array<String>): Pair<String, String>? {
|
||||
if (media == null) return null
|
||||
when (media.type) {
|
||||
ParcelableMedia.Type.VIDEO, ParcelableMedia.Type.ANIMATED_GIF -> {
|
||||
if (media.video_info == null) {
|
||||
return Pair.create<String, String>(media.media_url, null)
|
||||
}
|
||||
val firstMatch = media.video_info.variants.filter { variant ->
|
||||
supportedTypes.any { it.equals(variant.content_type, ignoreCase = true) }
|
||||
}.sortedByDescending(ParcelableMedia.VideoInfo.Variant::bitrate).firstOrNull() ?: return null
|
||||
return Pair.create(firstMatch.url, firstMatch.content_type)
|
||||
}
|
||||
ParcelableMedia.Type.CARD_ANIMATED_GIF -> {
|
||||
return Pair.create<String, String>(media.media_url, "video/mp4")
|
||||
}
|
||||
else -> {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePlayerState() {
|
||||
val playing = videoView.isPlaying
|
||||
|
@ -426,10 +419,21 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), IBaseFragment<Vide
|
|||
const val EXTRA_LOOP = "loop"
|
||||
const val EXTRA_DISABLE_CONTROL = "disable_control"
|
||||
const val EXTRA_DEFAULT_MUTE = "default_mute"
|
||||
private const val EXTRA_PAUSED_BY_USER = "paused_by_user"
|
||||
private const val EXTRA_PLAY_AUDIO = "play_audio"
|
||||
private val SUPPORTED_VIDEO_TYPES: Array<String>
|
||||
private val FALLBACK_VIDEO_TYPES: Array<String> = arrayOf("video/mp4")
|
||||
internal const val EXTRA_PAUSED_BY_USER = "paused_by_user"
|
||||
internal const val EXTRA_PLAY_AUDIO = "play_audio"
|
||||
internal val SUPPORTED_VIDEO_TYPES: Array<String>
|
||||
internal val FALLBACK_VIDEO_TYPES: Array<String> = arrayOf("video/mp4")
|
||||
|
||||
internal val MediaViewerFragment.isLoopEnabled: Boolean
|
||||
get() = arguments.getBoolean(EXTRA_LOOP, false)
|
||||
internal val MediaViewerFragment.isControlDisabled: Boolean
|
||||
get() = arguments.getBoolean(EXTRA_DISABLE_CONTROL, false)
|
||||
internal val MediaViewerFragment.isMutedByDefault: Boolean
|
||||
get() = arguments.getBoolean(EXTRA_DEFAULT_MUTE, false)
|
||||
internal val MediaViewerFragment.media: ParcelableMedia?
|
||||
get() = arguments.getParcelable<ParcelableMedia>(EXTRA_MEDIA)
|
||||
internal val MediaViewerFragment.accountKey: UserKey
|
||||
get() = arguments.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
|
||||
|
||||
init {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
|
@ -438,5 +442,28 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), IBaseFragment<Vide
|
|||
SUPPORTED_VIDEO_TYPES = arrayOf("video/webm", "video/mp4")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("SwitchIntDef")
|
||||
internal fun getBestVideoUrlAndType(media: ParcelableMedia?, supportedTypes: Array<String>): Pair<String, String>? {
|
||||
if (media == null) return null
|
||||
when (media.type) {
|
||||
ParcelableMedia.Type.VIDEO, ParcelableMedia.Type.ANIMATED_GIF -> {
|
||||
if (media.video_info == null) {
|
||||
return Pair.create<String, String>(media.media_url, null)
|
||||
}
|
||||
val firstMatch = media.video_info.variants.filter { variant ->
|
||||
supportedTypes.any { it.equals(variant.content_type, ignoreCase = true) }
|
||||
}.sortedByDescending(ParcelableMedia.VideoInfo.Variant::bitrate).firstOrNull() ?: return null
|
||||
return Pair.create(firstMatch.url, firstMatch.content_type)
|
||||
}
|
||||
ParcelableMedia.Type.CARD_ANIMATED_GIF -> {
|
||||
return Pair.create<String, String>(media.media_url, "video/mp4")
|
||||
}
|
||||
else -> {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
~ Twidere - Twitter client for Android
|
||||
~
|
||||
~ Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<com.google.android.exoplayer2.ui.SimpleExoPlayerView
|
||||
android:id="@+id/playerView"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerInParent="true"
|
||||
app:controller_layout_id="@layout/layout_media_viewer_video_controller_exo"
|
||||
app:resize_mode="fit"
|
||||
app:surface_type="texture_view"/>
|
|
@ -40,81 +40,5 @@
|
|||
|
||||
</com.commonsware.cwac.layouts.AspectLockedFrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/videoViewOverlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentBottom="true">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/videoControl"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?actionBarSize"
|
||||
android:layout_gravity="bottom"
|
||||
android:clickable="true"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
tools:ignore="UselessParent">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/playPauseButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/play"
|
||||
android:minWidth="@dimen/element_size_normal"
|
||||
android:src="@drawable/ic_action_play_arrow"/>
|
||||
|
||||
<org.mariotaku.twidere.view.FixedTextView
|
||||
android:id="@+id/positionLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@+id/videoViewProgress"
|
||||
android:layout_alignStart="@+id/videoViewProgress"
|
||||
android:layout_below="@+id/videoViewProgress"
|
||||
android:gravity="center"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/text_size_extra_small"
|
||||
tools:text="--:--"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/videoViewProgress"
|
||||
style="?android:progressBarStyleHorizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@+id/playPauseButton"
|
||||
android:layout_toLeftOf="@+id/volumeButton"
|
||||
android:layout_toRightOf="@+id/playPauseButton"
|
||||
android:layout_toStartOf="@+id/volumeButton"/>
|
||||
|
||||
<org.mariotaku.twidere.view.FixedTextView
|
||||
android:id="@+id/durationLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignEnd="@+id/videoViewProgress"
|
||||
android:layout_alignRight="@+id/videoViewProgress"
|
||||
android:layout_below="@+id/videoViewProgress"
|
||||
android:gravity="center"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/text_size_extra_small"
|
||||
tools:text="--:--"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/volumeButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/action_mute"
|
||||
android:minWidth="@dimen/element_size_normal"
|
||||
android:src="@drawable/ic_action_speaker_max"/>
|
||||
|
||||
</RelativeLayout>
|
||||
</FrameLayout>
|
||||
<include layout="@layout/layout_media_viewer_video_overlay"/>
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Twidere - Twitter client for Android
|
||||
~
|
||||
~ Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<RelativeLayout
|
||||
android:id="@+id/videoControl"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?actionBarSize"
|
||||
android:layout_gravity="bottom"
|
||||
android:clickable="true"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/playPauseContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true">
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_play"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/exo_controls_play_description"
|
||||
android:minWidth="@dimen/element_size_normal"
|
||||
android:src="@drawable/ic_action_play_arrow"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_pause"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/exo_controls_pause_description"
|
||||
android:minWidth="@dimen/element_size_normal"
|
||||
android:src="@drawable/ic_action_pause"
|
||||
tools:visibility="gone"/>
|
||||
</FrameLayout>
|
||||
|
||||
<org.mariotaku.twidere.view.FixedTextView
|
||||
android:id="@id/exo_position"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@id/exo_progress"
|
||||
android:layout_alignStart="@id/exo_progress"
|
||||
android:layout_below="@id/exo_progress"
|
||||
android:gravity="center"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/text_size_extra_small"
|
||||
tools:text="--:--"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@id/exo_progress"
|
||||
style="?android:progressBarStyleHorizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@+id/playPauseContainer"
|
||||
android:layout_toLeftOf="@+id/volumeButton"
|
||||
android:layout_toRightOf="@+id/playPauseContainer"
|
||||
android:layout_toStartOf="@+id/volumeButton"/>
|
||||
|
||||
<org.mariotaku.twidere.view.FixedTextView
|
||||
android:id="@id/exo_duration"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignEnd="@id/exo_progress"
|
||||
android:layout_alignRight="@id/exo_progress"
|
||||
android:layout_below="@id/exo_progress"
|
||||
android:gravity="center"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/text_size_extra_small"
|
||||
tools:text="--:--"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/volumeButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/action_mute"
|
||||
android:minWidth="@dimen/element_size_normal"
|
||||
android:src="@drawable/ic_action_speaker_max"/>
|
||||
|
||||
</RelativeLayout>
|
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Twidere - Twitter client for Android
|
||||
~
|
||||
~ Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/videoViewOverlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentBottom="true"
|
||||
tools:showIn="@layout/layout_media_viewer_texture_video_view">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/videoControl"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?actionBarSize"
|
||||
android:layout_gravity="bottom"
|
||||
android:clickable="true"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
tools:ignore="UselessParent">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/playPauseButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/play"
|
||||
android:minWidth="@dimen/element_size_normal"
|
||||
android:src="@drawable/ic_action_play_arrow"/>
|
||||
|
||||
<org.mariotaku.twidere.view.FixedTextView
|
||||
android:id="@+id/positionLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@+id/videoViewProgress"
|
||||
android:layout_alignStart="@+id/videoViewProgress"
|
||||
android:layout_below="@+id/videoViewProgress"
|
||||
android:gravity="center"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/text_size_extra_small"
|
||||
tools:text="--:--"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/videoViewProgress"
|
||||
style="?android:progressBarStyleHorizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@+id/playPauseButton"
|
||||
android:layout_toLeftOf="@+id/volumeButton"
|
||||
android:layout_toRightOf="@+id/playPauseButton"
|
||||
android:layout_toStartOf="@+id/volumeButton"/>
|
||||
|
||||
<org.mariotaku.twidere.view.FixedTextView
|
||||
android:id="@+id/durationLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignEnd="@+id/videoViewProgress"
|
||||
android:layout_alignRight="@+id/videoViewProgress"
|
||||
android:layout_below="@+id/videoViewProgress"
|
||||
android:gravity="center"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/text_size_extra_small"
|
||||
tools:text="--:--"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/volumeButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/action_mute"
|
||||
android:minWidth="@dimen/element_size_normal"
|
||||
android:src="@drawable/ic_action_speaker_max"/>
|
||||
|
||||
</RelativeLayout>
|
||||
</FrameLayout>
|
Loading…
Reference in New Issue