2020-10-21 16:40:22 +02:00
|
|
|
package org.schabi.newpipe.player.event
|
|
|
|
|
|
|
|
import android.content.Context
|
2020-10-21 16:41:14 +02:00
|
|
|
import android.os.Handler
|
2020-10-21 16:40:22 +02:00
|
|
|
import android.util.Log
|
|
|
|
import android.view.GestureDetector
|
|
|
|
import android.view.MotionEvent
|
|
|
|
import android.view.View
|
|
|
|
import android.view.ViewConfiguration
|
|
|
|
import org.schabi.newpipe.player.BasePlayer
|
|
|
|
import org.schabi.newpipe.player.MainPlayer
|
|
|
|
import org.schabi.newpipe.player.VideoPlayerImpl
|
|
|
|
import org.schabi.newpipe.player.helper.PlayerHelper
|
|
|
|
import org.schabi.newpipe.util.AnimationUtils
|
|
|
|
import kotlin.math.abs
|
|
|
|
import kotlin.math.hypot
|
|
|
|
import kotlin.math.max
|
2020-11-18 23:45:19 +01:00
|
|
|
import kotlin.math.min
|
2020-10-21 16:40:22 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Base gesture handling for [VideoPlayerImpl]
|
|
|
|
*
|
|
|
|
* This class contains the logic for the player gestures like View preparations
|
|
|
|
* and provides some abstract methods to make it easier separating the logic from the UI.
|
|
|
|
*/
|
|
|
|
abstract class BasePlayerGestureListener(
|
|
|
|
@JvmField
|
|
|
|
protected val playerImpl: VideoPlayerImpl,
|
|
|
|
@JvmField
|
|
|
|
protected val service: MainPlayer
|
|
|
|
) : GestureDetector.SimpleOnGestureListener(), View.OnTouchListener {
|
|
|
|
|
|
|
|
// ///////////////////////////////////////////////////////////////////
|
|
|
|
// Abstract methods for VIDEO and POPUP
|
|
|
|
// ///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
abstract fun onDoubleTap(event: MotionEvent, portion: DisplayPortion)
|
|
|
|
|
|
|
|
abstract fun onSingleTap(playerType: MainPlayer.PlayerType)
|
|
|
|
|
|
|
|
abstract fun onScroll(
|
|
|
|
playerType: MainPlayer.PlayerType,
|
|
|
|
portion: DisplayPortion,
|
|
|
|
initialEvent: MotionEvent,
|
|
|
|
movingEvent: MotionEvent,
|
|
|
|
distanceX: Float,
|
|
|
|
distanceY: Float
|
|
|
|
)
|
|
|
|
|
|
|
|
abstract fun onScrollEnd(playerType: MainPlayer.PlayerType, event: MotionEvent)
|
|
|
|
|
|
|
|
// ///////////////////////////////////////////////////////////////////
|
|
|
|
// Abstract methods for POPUP (exclusive)
|
|
|
|
// ///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
abstract fun onPopupResizingStart()
|
|
|
|
|
|
|
|
abstract fun onPopupResizingEnd()
|
|
|
|
|
|
|
|
private var initialPopupX: Int = -1
|
|
|
|
private var initialPopupY: Int = -1
|
|
|
|
|
|
|
|
private var isMovingInMain = false
|
|
|
|
private var isMovingInPopup = false
|
|
|
|
private var isResizing = false
|
|
|
|
|
2020-10-31 20:26:09 +01:00
|
|
|
private val tossFlingVelocity = PlayerHelper.getTossFlingVelocity()
|
2020-10-21 16:40:22 +02:00
|
|
|
|
|
|
|
// [popup] initial coordinates and distance between fingers
|
|
|
|
private var initPointerDistance = -1.0
|
|
|
|
private var initFirstPointerX = -1f
|
|
|
|
private var initFirstPointerY = -1f
|
|
|
|
private var initSecPointerX = -1f
|
|
|
|
private var initSecPointerY = -1f
|
|
|
|
|
|
|
|
// ///////////////////////////////////////////////////////////////////
|
|
|
|
// onTouch implementation
|
|
|
|
// ///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
|
|
|
return if (playerImpl.popupPlayerSelected()) {
|
|
|
|
onTouchInPopup(v, event)
|
|
|
|
} else {
|
|
|
|
onTouchInMain(v, event)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun onTouchInMain(v: View, event: MotionEvent): Boolean {
|
|
|
|
playerImpl.gestureDetector.onTouchEvent(event)
|
|
|
|
if (event.action == MotionEvent.ACTION_UP && isMovingInMain) {
|
|
|
|
isMovingInMain = false
|
|
|
|
onScrollEnd(MainPlayer.PlayerType.VIDEO, event)
|
|
|
|
}
|
|
|
|
return when (event.action) {
|
|
|
|
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> {
|
|
|
|
v.parent.requestDisallowInterceptTouchEvent(playerImpl.isFullscreen)
|
|
|
|
true
|
|
|
|
}
|
|
|
|
MotionEvent.ACTION_UP -> {
|
|
|
|
v.parent.requestDisallowInterceptTouchEvent(false)
|
|
|
|
false
|
|
|
|
}
|
|
|
|
else -> true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun onTouchInPopup(v: View, event: MotionEvent): Boolean {
|
|
|
|
playerImpl.gestureDetector.onTouchEvent(event)
|
|
|
|
if (event.pointerCount == 2 && !isMovingInPopup && !isResizing) {
|
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "onTouch() 2 finger pointer detected, enabling resizing.")
|
|
|
|
}
|
|
|
|
onPopupResizingStart()
|
|
|
|
|
|
|
|
// record coordinates of fingers
|
|
|
|
initFirstPointerX = event.getX(0)
|
|
|
|
initFirstPointerY = event.getY(0)
|
|
|
|
initSecPointerX = event.getX(1)
|
|
|
|
initSecPointerY = event.getY(1)
|
|
|
|
// record distance between fingers
|
2020-11-18 23:45:19 +01:00
|
|
|
initPointerDistance = hypot(initFirstPointerX - initSecPointerX.toDouble(),
|
2020-10-21 16:40:22 +02:00
|
|
|
initFirstPointerY - initSecPointerY.toDouble())
|
|
|
|
|
|
|
|
isResizing = true
|
|
|
|
}
|
|
|
|
if (event.action == MotionEvent.ACTION_MOVE && !isMovingInPopup && isResizing) {
|
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "onTouch() ACTION_MOVE > v = [$v], e1.getRaw = [${event.rawX}" +
|
|
|
|
", ${event.rawY}]")
|
|
|
|
}
|
|
|
|
return handleMultiDrag(event)
|
|
|
|
}
|
|
|
|
if (event.action == MotionEvent.ACTION_UP) {
|
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "onTouch() ACTION_UP > v = [$v], e1.getRaw = [${event.rawX}" +
|
|
|
|
", ${event.rawY}]")
|
|
|
|
}
|
|
|
|
if (isMovingInPopup) {
|
|
|
|
isMovingInPopup = false
|
|
|
|
onScrollEnd(MainPlayer.PlayerType.POPUP, event)
|
|
|
|
}
|
|
|
|
if (isResizing) {
|
|
|
|
isResizing = false
|
|
|
|
|
|
|
|
initPointerDistance = (-1).toDouble()
|
|
|
|
initFirstPointerX = (-1).toFloat()
|
|
|
|
initFirstPointerY = (-1).toFloat()
|
|
|
|
initSecPointerX = (-1).toFloat()
|
|
|
|
initSecPointerY = (-1).toFloat()
|
|
|
|
|
|
|
|
onPopupResizingEnd()
|
|
|
|
playerImpl.changeState(playerImpl.currentState)
|
|
|
|
}
|
|
|
|
if (!playerImpl.isPopupClosing) {
|
|
|
|
playerImpl.savePositionAndSize()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
v.performClick()
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun handleMultiDrag(event: MotionEvent): Boolean {
|
|
|
|
if (initPointerDistance != -1.0 && event.pointerCount == 2) {
|
|
|
|
// get the movements of the fingers
|
|
|
|
val firstPointerMove = hypot(event.getX(0) - initFirstPointerX.toDouble(),
|
|
|
|
event.getY(0) - initFirstPointerY.toDouble())
|
|
|
|
val secPointerMove = hypot(event.getX(1) - initSecPointerX.toDouble(),
|
|
|
|
event.getY(1) - initSecPointerY.toDouble())
|
|
|
|
|
|
|
|
// minimum threshold beyond which pinch gesture will work
|
|
|
|
val minimumMove = ViewConfiguration.get(service).scaledTouchSlop
|
|
|
|
|
|
|
|
if (max(firstPointerMove, secPointerMove) > minimumMove) {
|
|
|
|
// calculate current distance between the pointers
|
|
|
|
val currentPointerDistance = hypot(event.getX(0) - event.getX(1).toDouble(),
|
|
|
|
event.getY(0) - event.getY(1).toDouble())
|
|
|
|
|
|
|
|
val popupWidth = playerImpl.popupWidth.toDouble()
|
|
|
|
// change co-ordinates of popup so the center stays at the same position
|
|
|
|
val newWidth = popupWidth * currentPointerDistance / initPointerDistance
|
|
|
|
initPointerDistance = currentPointerDistance
|
|
|
|
playerImpl.popupLayoutParams.x += ((popupWidth - newWidth) / 2.0).toInt()
|
|
|
|
|
|
|
|
playerImpl.checkPopupPositionBounds()
|
|
|
|
playerImpl.updateScreenSize()
|
|
|
|
|
|
|
|
playerImpl.updatePopupSize(
|
2020-11-18 23:45:19 +01:00
|
|
|
min(playerImpl.screenWidth.toDouble(), newWidth).toInt(),
|
2020-10-21 16:40:22 +02:00
|
|
|
-1)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// ///////////////////////////////////////////////////////////////////
|
|
|
|
// Simple gestures
|
|
|
|
// ///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
override fun onDown(e: MotionEvent): Boolean {
|
|
|
|
if (DEBUG)
|
|
|
|
Log.d(TAG, "onDown called with e = [$e]")
|
|
|
|
|
2020-10-21 16:41:14 +02:00
|
|
|
if (isDoubleTapping && isDoubleTapEnabled) {
|
|
|
|
doubleTapControls?.onDoubleTapProgressDown(getDisplayPortion(e))
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-10-21 16:40:22 +02:00
|
|
|
return if (playerImpl.popupPlayerSelected())
|
|
|
|
onDownInPopup(e)
|
|
|
|
else
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun onDownInPopup(e: MotionEvent): Boolean {
|
|
|
|
// Fix popup position when the user touch it, it may have the wrong one
|
|
|
|
// because the soft input is visible (the draggable area is currently resized).
|
|
|
|
playerImpl.updateScreenSize()
|
|
|
|
playerImpl.checkPopupPositionBounds()
|
|
|
|
initialPopupX = playerImpl.popupLayoutParams.x
|
|
|
|
initialPopupY = playerImpl.popupLayoutParams.y
|
|
|
|
playerImpl.popupWidth = playerImpl.popupLayoutParams.width.toFloat()
|
|
|
|
playerImpl.popupHeight = playerImpl.popupLayoutParams.height.toFloat()
|
|
|
|
return super.onDown(e)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onDoubleTap(e: MotionEvent): Boolean {
|
|
|
|
if (DEBUG)
|
|
|
|
Log.d(TAG, "onDoubleTap called with e = [$e]")
|
|
|
|
|
|
|
|
onDoubleTap(e, getDisplayPortion(e))
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
|
|
|
|
if (DEBUG)
|
|
|
|
Log.d(TAG, "onSingleTapConfirmed() called with: e = [$e]")
|
|
|
|
|
2020-10-21 16:41:14 +02:00
|
|
|
if (isDoubleTapping)
|
|
|
|
return true
|
|
|
|
|
2020-10-21 16:40:22 +02:00
|
|
|
if (playerImpl.popupPlayerSelected()) {
|
|
|
|
if (playerImpl.player == null)
|
|
|
|
return false
|
|
|
|
|
|
|
|
onSingleTap(MainPlayer.PlayerType.POPUP)
|
|
|
|
return true
|
|
|
|
} else {
|
|
|
|
super.onSingleTapConfirmed(e)
|
|
|
|
if (playerImpl.currentState == BasePlayer.STATE_BLOCKED)
|
|
|
|
return true
|
|
|
|
|
|
|
|
onSingleTap(MainPlayer.PlayerType.VIDEO)
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onLongPress(e: MotionEvent?) {
|
|
|
|
if (playerImpl.popupPlayerSelected()) {
|
|
|
|
playerImpl.updateScreenSize()
|
|
|
|
playerImpl.checkPopupPositionBounds()
|
|
|
|
playerImpl.updatePopupSize(playerImpl.screenWidth.toInt(), -1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onScroll(
|
|
|
|
initialEvent: MotionEvent,
|
|
|
|
movingEvent: MotionEvent,
|
|
|
|
distanceX: Float,
|
|
|
|
distanceY: Float
|
|
|
|
): Boolean {
|
|
|
|
return if (playerImpl.popupPlayerSelected()) {
|
|
|
|
onScrollInPopup(initialEvent, movingEvent, distanceX, distanceY)
|
|
|
|
} else {
|
|
|
|
onScrollInMain(initialEvent, movingEvent, distanceX, distanceY)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onFling(
|
|
|
|
e1: MotionEvent?,
|
|
|
|
e2: MotionEvent?,
|
|
|
|
velocityX: Float,
|
|
|
|
velocityY: Float
|
|
|
|
): Boolean {
|
|
|
|
return if (playerImpl.popupPlayerSelected()) {
|
|
|
|
val absVelocityX = abs(velocityX)
|
|
|
|
val absVelocityY = abs(velocityY)
|
|
|
|
if (absVelocityX.coerceAtLeast(absVelocityY) > tossFlingVelocity) {
|
|
|
|
if (absVelocityX > tossFlingVelocity) {
|
|
|
|
playerImpl.popupLayoutParams.x = velocityX.toInt()
|
|
|
|
}
|
|
|
|
if (absVelocityY > tossFlingVelocity) {
|
|
|
|
playerImpl.popupLayoutParams.y = velocityY.toInt()
|
|
|
|
}
|
|
|
|
playerImpl.checkPopupPositionBounds()
|
|
|
|
playerImpl.windowManager
|
|
|
|
.updateViewLayout(playerImpl.rootView, playerImpl.popupLayoutParams)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun onScrollInMain(
|
|
|
|
initialEvent: MotionEvent,
|
|
|
|
movingEvent: MotionEvent,
|
|
|
|
distanceX: Float,
|
|
|
|
distanceY: Float
|
|
|
|
): Boolean {
|
|
|
|
|
|
|
|
if (!playerImpl.isFullscreen) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
val isTouchingStatusBar: Boolean = initialEvent.y < getStatusBarHeight(service)
|
|
|
|
val isTouchingNavigationBar: Boolean = (initialEvent.y
|
|
|
|
> playerImpl.rootView.height - getNavigationBarHeight(service))
|
|
|
|
if (isTouchingStatusBar || isTouchingNavigationBar) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
val insideThreshold = abs(movingEvent.y - initialEvent.y) <= MOVEMENT_THRESHOLD
|
|
|
|
if (!isMovingInMain && (insideThreshold || abs(distanceX) > abs(distanceY)) ||
|
|
|
|
playerImpl.currentState == BasePlayer.STATE_COMPLETED) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
isMovingInMain = true
|
|
|
|
|
|
|
|
onScroll(MainPlayer.PlayerType.VIDEO, getDisplayHalfPortion(initialEvent),
|
|
|
|
initialEvent, movingEvent, distanceX, distanceY)
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun onScrollInPopup(
|
|
|
|
initialEvent: MotionEvent,
|
|
|
|
movingEvent: MotionEvent,
|
|
|
|
distanceX: Float,
|
|
|
|
distanceY: Float
|
|
|
|
): Boolean {
|
|
|
|
|
|
|
|
if (isResizing) {
|
|
|
|
return super.onScroll(initialEvent, movingEvent, distanceX, distanceY)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isMovingInPopup) {
|
|
|
|
AnimationUtils.animateView(playerImpl.closeOverlayButton, true, 200)
|
|
|
|
}
|
|
|
|
|
|
|
|
isMovingInPopup = true
|
|
|
|
|
|
|
|
val diffX: Float = (movingEvent.rawX - initialEvent.rawX)
|
|
|
|
var posX: Float = (initialPopupX + diffX)
|
|
|
|
val diffY: Float = (movingEvent.rawY - initialEvent.rawY)
|
|
|
|
var posY: Float = (initialPopupY + diffY)
|
|
|
|
|
|
|
|
if (posX > playerImpl.screenWidth - playerImpl.popupWidth) {
|
|
|
|
posX = (playerImpl.screenWidth - playerImpl.popupWidth)
|
|
|
|
} else if (posX < 0) {
|
|
|
|
posX = 0f
|
|
|
|
}
|
|
|
|
|
|
|
|
if (posY > playerImpl.screenHeight - playerImpl.popupHeight) {
|
|
|
|
posY = (playerImpl.screenHeight - playerImpl.popupHeight)
|
|
|
|
} else if (posY < 0) {
|
|
|
|
posY = 0f
|
|
|
|
}
|
|
|
|
|
|
|
|
playerImpl.popupLayoutParams.x = posX.toInt()
|
|
|
|
playerImpl.popupLayoutParams.y = posY.toInt()
|
|
|
|
|
|
|
|
onScroll(MainPlayer.PlayerType.POPUP, getDisplayHalfPortion(initialEvent),
|
|
|
|
initialEvent, movingEvent, distanceX, distanceY)
|
|
|
|
|
|
|
|
playerImpl.windowManager
|
|
|
|
.updateViewLayout(playerImpl.rootView, playerImpl.popupLayoutParams)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-10-21 16:41:14 +02:00
|
|
|
// ///////////////////////////////////////////////////////////////////
|
|
|
|
// Multi double tapping
|
|
|
|
// ///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
var doubleTapControls: DoubleTapListener? = null
|
|
|
|
private set
|
|
|
|
|
|
|
|
val isDoubleTapEnabled: Boolean
|
|
|
|
get() = doubleTapDelay > 0
|
|
|
|
|
|
|
|
var isDoubleTapping = false
|
|
|
|
private set
|
|
|
|
|
|
|
|
fun doubleTapControls(listener: DoubleTapListener) = apply {
|
|
|
|
doubleTapControls = listener
|
|
|
|
}
|
|
|
|
|
|
|
|
private var doubleTapDelay = DOUBLE_TAP_DELAY
|
|
|
|
private val doubleTapHandler: Handler = Handler()
|
|
|
|
private val doubleTapRunnable = Runnable {
|
|
|
|
if (DEBUG)
|
|
|
|
Log.d(TAG, "doubleTapRunnable called")
|
|
|
|
|
|
|
|
isDoubleTapping = false
|
|
|
|
doubleTapControls?.onDoubleTapFinished()
|
|
|
|
}
|
|
|
|
|
|
|
|
fun startMultiDoubleTap(e: MotionEvent) {
|
|
|
|
if (!isDoubleTapping) {
|
|
|
|
if (DEBUG)
|
|
|
|
Log.d(TAG, "startMultiDoubleTap called with e = [$e]")
|
|
|
|
|
|
|
|
keepInDoubleTapMode()
|
|
|
|
doubleTapControls?.onDoubleTapStarted(getDisplayPortion(e))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fun keepInDoubleTapMode() {
|
|
|
|
if (DEBUG)
|
|
|
|
Log.d(TAG, "keepInDoubleTapMode called")
|
|
|
|
|
|
|
|
isDoubleTapping = true
|
|
|
|
doubleTapHandler.removeCallbacks(doubleTapRunnable)
|
|
|
|
doubleTapHandler.postDelayed(doubleTapRunnable, doubleTapDelay)
|
|
|
|
}
|
|
|
|
|
|
|
|
fun endMultiDoubleTap() {
|
|
|
|
if (DEBUG)
|
|
|
|
Log.d(TAG, "endMultiDoubleTap called")
|
|
|
|
|
|
|
|
isDoubleTapping = false
|
|
|
|
doubleTapHandler.removeCallbacks(doubleTapRunnable)
|
|
|
|
doubleTapControls?.onDoubleTapFinished()
|
|
|
|
}
|
|
|
|
|
|
|
|
fun enableMultiDoubleTap(enable: Boolean) = apply {
|
|
|
|
doubleTapDelay = if (enable) DOUBLE_TAP_DELAY else 0
|
|
|
|
}
|
|
|
|
|
2020-10-21 16:40:22 +02:00
|
|
|
// ///////////////////////////////////////////////////////////////////
|
|
|
|
// Utils
|
|
|
|
// ///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
private fun getDisplayPortion(e: MotionEvent): DisplayPortion {
|
|
|
|
return if (playerImpl.playerType == MainPlayer.PlayerType.POPUP) {
|
|
|
|
when {
|
|
|
|
e.x < playerImpl.popupWidth / 3.0 -> DisplayPortion.LEFT
|
|
|
|
e.x > playerImpl.popupWidth * 2.0 / 3.0 -> DisplayPortion.RIGHT
|
|
|
|
else -> DisplayPortion.MIDDLE
|
|
|
|
}
|
|
|
|
} else /* MainPlayer.PlayerType.VIDEO */ {
|
|
|
|
when {
|
|
|
|
e.x < playerImpl.rootView.width / 3.0 -> DisplayPortion.LEFT
|
|
|
|
e.x > playerImpl.rootView.width * 2.0 / 3.0 -> DisplayPortion.RIGHT
|
|
|
|
else -> DisplayPortion.MIDDLE
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Currently needed for scrolling since there is no action more the middle portion
|
|
|
|
private fun getDisplayHalfPortion(e: MotionEvent): DisplayPortion {
|
|
|
|
return if (playerImpl.playerType == MainPlayer.PlayerType.POPUP) {
|
|
|
|
when {
|
|
|
|
e.x < playerImpl.popupWidth / 2.0 -> DisplayPortion.LEFT_HALF
|
|
|
|
else -> DisplayPortion.RIGHT_HALF
|
|
|
|
}
|
|
|
|
} else /* MainPlayer.PlayerType.VIDEO */ {
|
|
|
|
when {
|
|
|
|
e.x < playerImpl.rootView.width / 2.0 -> DisplayPortion.LEFT_HALF
|
|
|
|
else -> DisplayPortion.RIGHT_HALF
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun getNavigationBarHeight(context: Context): Int {
|
|
|
|
val resId = context.resources
|
|
|
|
.getIdentifier("navigation_bar_height", "dimen", "android")
|
|
|
|
return if (resId > 0) {
|
|
|
|
context.resources.getDimensionPixelSize(resId)
|
|
|
|
} else 0
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun getStatusBarHeight(context: Context): Int {
|
|
|
|
val resId = context.resources
|
|
|
|
.getIdentifier("status_bar_height", "dimen", "android")
|
|
|
|
return if (resId > 0) {
|
|
|
|
context.resources.getDimensionPixelSize(resId)
|
|
|
|
} else 0
|
|
|
|
}
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
private const val TAG = "BasePlayerGestListener"
|
|
|
|
private val DEBUG = BasePlayer.DEBUG
|
|
|
|
|
2020-10-21 16:41:14 +02:00
|
|
|
private const val DOUBLE_TAP_DELAY = 550L
|
2020-10-21 16:40:22 +02:00
|
|
|
private const val MOVEMENT_THRESHOLD = 40
|
|
|
|
}
|
|
|
|
}
|