Restore pinch to zoom gesture in in-app camera.
This commit is contained in:
parent
ba70101efd
commit
9f47a41017
1 changed files with 38 additions and 7 deletions
|
@ -9,8 +9,10 @@ import android.Manifest
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Size
|
import android.util.Size
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
|
import android.view.ScaleGestureDetector
|
||||||
import android.view.Surface
|
import android.view.Surface
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewConfiguration
|
||||||
import androidx.annotation.MainThread
|
import androidx.annotation.MainThread
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.annotation.RequiresPermission
|
import androidx.annotation.RequiresPermission
|
||||||
|
@ -53,6 +55,8 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil
|
import org.thoughtcrime.securesms.util.ViewUtil
|
||||||
import org.thoughtcrime.securesms.util.visible
|
import org.thoughtcrime.securesms.util.visible
|
||||||
import java.util.concurrent.Executor
|
import java.util.concurrent.Executor
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a class to manage the camera resource, and relies on the AndroidX CameraX library.
|
* This is a class to manage the camera resource, and relies on the AndroidX CameraX library.
|
||||||
|
@ -81,6 +85,7 @@ class SignalCameraController(
|
||||||
private val imageMode = CameraXUtil.getOptimalCaptureMode()
|
private val imageMode = CameraXUtil.getOptimalCaptureMode()
|
||||||
|
|
||||||
private val cameraProviderFuture: ListenableFuture<ProcessCameraProvider> = ProcessCameraProvider.getInstance(context)
|
private val cameraProviderFuture: ListenableFuture<ProcessCameraProvider> = ProcessCameraProvider.getInstance(context)
|
||||||
|
private val scaleGestureDetector = ScaleGestureDetector(context, PinchToZoomGestureListener())
|
||||||
private val viewPort: ViewPort? = previewView.getViewPort(Surface.ROTATION_0)
|
private val viewPort: ViewPort? = previewView.getViewPort(Surface.ROTATION_0)
|
||||||
private val initializationCompleteListeners: MutableSet<InitializationListener> = mutableSetOf()
|
private val initializationCompleteListeners: MutableSet<InitializationListener> = mutableSetOf()
|
||||||
private val customUseCases: MutableList<UseCase> = mutableListOf()
|
private val customUseCases: MutableList<UseCase> = mutableListOf()
|
||||||
|
@ -137,7 +142,7 @@ class SignalCameraController(
|
||||||
buildUseCaseGroup()
|
buildUseCaseGroup()
|
||||||
)
|
)
|
||||||
|
|
||||||
initializeTapToFocus(camera)
|
initializeTapToFocusAndPinchToZoom(camera)
|
||||||
this.cameraProperty = camera
|
this.cameraProperty = camera
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Use case binding failed", e)
|
Log.e(TAG, "Use case binding failed", e)
|
||||||
|
@ -394,18 +399,18 @@ class SignalCameraController(
|
||||||
}.build()
|
}.build()
|
||||||
|
|
||||||
@MainThread
|
@MainThread
|
||||||
private fun initializeTapToFocus(camera: Camera) {
|
private fun initializeTapToFocusAndPinchToZoom(camera: Camera) {
|
||||||
ThreadUtil.assertMainThread()
|
ThreadUtil.assertMainThread()
|
||||||
previewView.setOnTouchListener { v: View?, event: MotionEvent ->
|
previewView.setOnTouchListener { v: View?, event: MotionEvent ->
|
||||||
if (event.action == MotionEvent.ACTION_DOWN) {
|
val isSingleTouch = event.pointerCount == 1
|
||||||
return@setOnTouchListener true
|
val isUpEvent = event.action == MotionEvent.ACTION_UP
|
||||||
}
|
val notALongPress = (event.eventTime - event.downTime < ViewConfiguration.getLongPressTimeout())
|
||||||
if (event.action == MotionEvent.ACTION_UP) {
|
if (isSingleTouch && isUpEvent && notALongPress) {
|
||||||
focusAndMeterOnPoint(camera, event.x, event.y)
|
focusAndMeterOnPoint(camera, event.x, event.y)
|
||||||
v?.performClick()
|
v?.performClick()
|
||||||
return@setOnTouchListener true
|
return@setOnTouchListener true
|
||||||
}
|
}
|
||||||
false
|
return@setOnTouchListener scaleGestureDetector.onTouchEvent(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,6 +453,21 @@ class SignalCameraController(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MainThread
|
||||||
|
private fun onPinchToZoom(pinchToZoomScale: Float) {
|
||||||
|
val zoomState = getZoomState().getValue() ?: return
|
||||||
|
var clampedRatio: Float = zoomState.zoomRatio * if (pinchToZoomScale > 1f) {
|
||||||
|
1.0f + (pinchToZoomScale - 1.0f) * 2
|
||||||
|
} else {
|
||||||
|
1.0f - (1.0f - pinchToZoomScale) * 2
|
||||||
|
}
|
||||||
|
clampedRatio = min(
|
||||||
|
max(clampedRatio.toDouble(), zoomState.minZoomRatio.toDouble()),
|
||||||
|
zoomState.maxZoomRatio.toDouble()
|
||||||
|
).toFloat()
|
||||||
|
setZoomRatio(clampedRatio)
|
||||||
|
}
|
||||||
|
|
||||||
private fun isRecording(): Boolean {
|
private fun isRecording(): Boolean {
|
||||||
return recording != null
|
return recording != null
|
||||||
}
|
}
|
||||||
|
@ -472,6 +492,17 @@ class SignalCameraController(
|
||||||
return Size(this.height, this.width)
|
return Size(this.height, this.width)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inner class PinchToZoomGestureListener : ScaleGestureDetector.OnScaleGestureListener {
|
||||||
|
override fun onScale(detector: ScaleGestureDetector): Boolean {
|
||||||
|
onPinchToZoom(detector.scaleFactor)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onScaleBegin(detector: ScaleGestureDetector): Boolean = true
|
||||||
|
|
||||||
|
override fun onScaleEnd(detector: ScaleGestureDetector) = Unit
|
||||||
|
}
|
||||||
|
|
||||||
interface InitializationListener {
|
interface InitializationListener {
|
||||||
fun onInitialized(cameraProvider: ProcessCameraProvider)
|
fun onInitialized(cameraProvider: ProcessCameraProvider)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue