Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for video messaging back into the DOM & other enhancements #92

Merged
merged 1 commit into from
Jul 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ abstract class BaseActivity<B: ViewDataBinding> : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Log.i("LOLZ", this.javaClass.toString())
// Log.i("LOLZ", layout().toString())
binding = DataBindingUtil.setContentView(this, layout())
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@ import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.source.hls.HlsMediaSource
import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory
import org.greenrobot.eventbus.EventBus
import to.dev.dev_android.BuildConfig
import to.dev.dev_android.R
import to.dev.dev_android.databinding.ActivityVideoPlayerBinding
import to.dev.dev_android.events.VideoPlayerPauseEvent
import to.dev.dev_android.events.VideoPlayerTickEvent
import to.dev.dev_android.webclients.CustomWebViewClient
import java.util.*

class VideoPlayerActivity : BaseActivity<ActivityVideoPlayerBinding>() {

private var player: SimpleExoPlayer? = null
private val timer = Timer()

override fun layout(): Int {
return R.layout.activity_video_player
Expand All @@ -36,13 +42,28 @@ class VideoPlayerActivity : BaseActivity<ActivityVideoPlayerBinding>() {
player?.prepare(mediaSource)
player?.seekTo(videoTime.toLong() * 1000)
player?.playWhenReady = true

val timeUpdateTask = object: TimerTask() {
override fun run() {
timeUpdate()
}
}
timer.schedule(timeUpdateTask, 0, 1000)
}

override fun onDestroy() {
player?.playWhenReady = false
timer.cancel()
EventBus.getDefault().post(VideoPlayerPauseEvent())
super.onDestroy()
}

fun timeUpdate() {
val milliseconds = (player?.currentPosition ?: 0)
val currentTime = (milliseconds / 1000).toString()
EventBus.getDefault().post(VideoPlayerTickEvent(currentTime))
}

companion object {
@MainThread
fun newIntent(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package to.dev.dev_android.events

class VideoPlayerPauseEvent {
val action = "pause"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package to.dev.dev_android.events

class VideoPlayerTickEvent(val seconds: String) {
val action = "tick"
}
58 changes: 47 additions & 11 deletions app/src/main/java/to/dev/dev_android/util/AndroidWebViewBridge.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@ import android.util.Log
import android.webkit.JavascriptInterface
import android.widget.Toast
import com.google.gson.Gson
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import to.dev.dev_android.activities.VideoPlayerActivity
import to.dev.dev_android.events.VideoPlayerPauseEvent
import to.dev.dev_android.events.VideoPlayerTickEvent
import to.dev.dev_android.media.AudioService
import to.dev.dev_android.webclients.CustomWebViewClient
import to.dev.dev_android.activities.VideoPlayerActivity
import java.util.*

class AndroidWebViewBridge(private val context: Context) {

var webViewClient: CustomWebViewClient? = null
private val timer = Timer()
private var timer: Timer? = null

// audioService is initialized when onServiceConnected is executed after/during binding is done
private var audioService: AudioService? = null
Expand Down Expand Up @@ -65,13 +70,27 @@ class AndroidWebViewBridge(private val context: Context) {
}

@JavascriptInterface
fun playVideo(url: String, seconds: String) {
// Pause the audio player in case the user is currently listening to a audio (podcast)
audioService?.pause()
fun videoMessage(message: String) {
var map: Map<String, String> = HashMap()
map = Gson().fromJson(message, map.javaClass)
when(map["action"]) {
"play" -> playVideo(map["url"], map["seconds"])
else -> logError("Video Error", "Unknown action")
}
}

// Launch VideoPlayerActivity
val intent = VideoPlayerActivity.newIntent(context, url, seconds)
context.startActivity(intent)
fun playVideo(url: String?, seconds: String?) {
url?.let {
// Pause the audio player in case the user is currently listening to a audio (podcast)
audioService?.pause()
timer?.cancel()

// Launch VideoPlayerActivity
val intent = VideoPlayerActivity.newIntent(context, url, seconds ?: "0")
context.startActivity(intent)

EventBus.getDefault().register(this)
}
}

fun loadPodcast(url: String?) {
Expand All @@ -81,15 +100,20 @@ class AndroidWebViewBridge(private val context: Context) {
context.bindService(intent, connection, Context.BIND_AUTO_CREATE)
}

// Clear out lingering timer if it exists & recreate
timer?.cancel()
timer = Timer()
val timeUpdateTask = object: TimerTask() {
override fun run() {
podcastTimeUpdate()
}
}
timer.schedule(timeUpdateTask, 0, 1000)
timer?.schedule(timeUpdateTask, 0, 1000)
}

fun terminatePodcast() {
timer?.cancel()
timer = null
audioService?.pause()
context.unbindService(connection)
audioService = null
Expand All @@ -102,11 +126,23 @@ class AndroidWebViewBridge(private val context: Context) {
val duration = it.durationInSec() / 1000
if (duration < 0) {
// The duration overflows into a negative when waiting to load audio (initializing)
webViewClient?.sendPodcastMessage(mapOf("action" to "init"))
webViewClient?.sendBridgeMessage("podcast", mapOf("action" to "init"))
} else {
val message = mapOf("action" to "tick", "duration" to duration, "currentTime" to time)
webViewClient?.sendPodcastMessage(message)
webViewClient?.sendBridgeMessage("podcast", message)
}
}
}

@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: VideoPlayerPauseEvent) {
webViewClient?.sendBridgeMessage("video", mapOf("action" to event.action))
EventBus.getDefault().unregister(this)
}

@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: VideoPlayerTickEvent) {
val message = mapOf("action" to event.action, "currentTime" to event.seconds)
webViewClient?.sendBridgeMessage("video", message)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,14 @@ class CustomWebViewClient(
return true
}

fun sendPodcastMessage(message: Map<String, Any>) {
fun sendBridgeMessage(type: String, message: Map<String, Any>) {
val jsonMessage = JSONObject(message).toString()
val javascript = "document.getElementById('audiocontent').setAttribute('data-podcast', '$jsonMessage')"
var javascript = ""
when(type) {
"podcast" -> javascript = "document.getElementById('audiocontent').setAttribute('data-podcast', '$jsonMessage')"
"video" -> javascript = "document.getElementById('video-player-source').setAttribute('data-message', '$jsonMessage')"
else -> return
}
view?.post(Runnable {
view?.evaluateJavascript(javascript, null)
})
Expand Down