Aperture: Add support for video recording pause/resume
Change-Id: I2e9781fcdf932be8619756c953fd5fc2d2d145c6
diff --git a/app/src/main/java/org/lineageos/aperture/MainActivity.kt b/app/src/main/java/org/lineageos/aperture/MainActivity.kt
index f540310..8e5e06e 100644
--- a/app/src/main/java/org/lineageos/aperture/MainActivity.kt
+++ b/app/src/main/java/org/lineageos/aperture/MainActivity.kt
@@ -110,6 +110,7 @@
private val videoDuration by lazy { findViewById<MaterialButton>(R.id.videoDuration) }
private val videoModeButton by lazy { findViewById<MaterialButton>(R.id.videoModeButton) }
private val videoQualityButton by lazy { findViewById<ToggleButton>(R.id.videoQualityButton) }
+ private val videoRecordingStateButton by lazy { findViewById<ImageButton>(R.id.videoRecordingStateButton) }
private val viewFinder by lazy { findViewById<PreviewView>(R.id.viewFinder) }
private val viewFinderFocus by lazy { findViewById<ImageView>(R.id.viewFinderFocus) }
private val zoomLevel by lazy { findViewById<Slider>(R.id.zoomLevel) }
@@ -149,6 +150,7 @@
get() = sharedPreferences.videoQuality
private var recording: Recording? = null
private val recordingLock = Mutex()
+ private var recordingPaused = false
private val sharedPreferences by lazy {
PreferenceManager.getDefaultSharedPreferences(this)
@@ -212,6 +214,12 @@
VideoEnd(R.drawable.avd_video_end),
}
+ enum class VideoRecordingStateAnimation(val resourceId: Int) {
+ Init(R.drawable.avd_video_recording_pause),
+ ResumeToPause(R.drawable.avd_video_recording_pause),
+ PauseToResume(R.drawable.avd_video_recording_resume),
+ }
+
@SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -357,6 +365,14 @@
flipCameraButton.setOnClickListener { flipCamera() }
+ videoRecordingStateButton.setOnClickListener {
+ if (recordingPaused) {
+ recording?.resume()
+ } else {
+ recording?.pause()
+ }
+ }
+
// Initialize shutter drawable
when (cameraMode) {
CameraMode.PHOTO -> startShutterAnimation(ShutterAnimation.InitPhoto)
@@ -488,6 +504,22 @@
}
}
+ private fun startVideoRecordingStateAnimation(animation: VideoRecordingStateAnimation) {
+ // Get appropriate drawable
+ val drawable = ContextCompat.getDrawable(
+ this, animation.resourceId
+ ) as AnimatedVectorDrawable
+
+ // Update current drawable
+ videoRecordingStateButton.setImageDrawable(drawable)
+
+ // Start or reset animation
+ when (animation) {
+ VideoRecordingStateAnimation.Init -> drawable.reset()
+ else -> drawable.start()
+ }
+ }
+
private fun takePhoto() {
// Bail out if a photo is already being taken
if (isTakingPhoto) {
@@ -567,9 +599,27 @@
// Update duration text and visibility state
videoDuration.text = TimeUtils.convertNanosToString(duration)
videoDuration.isVisible = enabled
+
+ // Update video recording pause/resume button visibility state
+ if (duration == 0L) {
+ flipCameraButton.isInvisible = enabled
+ videoRecordingStateButton.isVisible = enabled
+ }
}
when (it) {
+ is VideoRecordEvent.Start -> runOnUiThread {
+ recordingPaused = false
+ startVideoRecordingStateAnimation(VideoRecordingStateAnimation.Init)
+ }
+ is VideoRecordEvent.Pause -> runOnUiThread {
+ recordingPaused = true
+ startVideoRecordingStateAnimation(VideoRecordingStateAnimation.ResumeToPause)
+ }
+ is VideoRecordEvent.Resume -> runOnUiThread {
+ recordingPaused = false
+ startVideoRecordingStateAnimation(VideoRecordingStateAnimation.PauseToResume)
+ }
is VideoRecordEvent.Status -> runOnUiThread {
updateRecordingStatus(true, it.recordingStats.recordedDurationNanos)
}
diff --git a/app/src/main/res/drawable/avd_video_recording_pause.xml b/app/src/main/res/drawable/avd_video_recording_pause.xml
new file mode 100644
index 0000000..0563cce
--- /dev/null
+++ b/app/src/main/res/drawable/avd_video_recording_pause.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ SPDX-FileCopyrightText: 2022 The LineageOS Project
+ SPDX-License-Identifier: Apache-2.0
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:name="vector"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="32"
+ android:viewportHeight="32">
+ <path
+ android:name="backplate"
+ android:fillColor="@color/gray_10"
+ android:pathData="M 16 1 C 12.023 1 8.205 2.581 5.393 5.393 C 2.581 8.205 1 12.023 1 16 C 1 19.977 2.581 23.795 5.393 26.607 C 8.205 29.419 12.023 31 16 31 C 19.976 31 23.794 29.419 26.606 26.607 C 29.418 23.795 31 19.977 31 16 C 31 12.023 29.418 8.205 26.606 5.393 C 23.794 2.581 19.976 1 16 1 Z"
+ android:strokeWidth="2"
+ android:strokeColor="@color/white" />
+ <group
+ android:name="ic_pause"
+ android:pivotX="16"
+ android:pivotY="16">
+ <path
+ android:name="pause"
+ android:fillColor="@color/gray_60"
+ android:pathData="M 14 9 L 10 9 L 10 23 L 14 23 L 14 9 Z M 22 9 L 18 9 L 18 23 L 22 23 L 22 9 Z" />
+ </group>
+ <group
+ android:name="ic_play"
+ android:pivotX="16"
+ android:pivotY="16"
+ android:translateX="8">
+ <path
+ android:name="play"
+ android:fillAlpha="0"
+ android:fillColor="@color/white"
+ android:pathData="M 11.5 9 L 22.5 16 L 11.5 23 L 11.5 9 Z" />
+ </group>
+ </vector>
+ </aapt:attr>
+ <target android:name="backplate">
+ <aapt:attr name="android:animation">
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/linear_interpolator"
+ android:propertyName="fillColor"
+ android:startOffset="100"
+ android:valueFrom="@color/gray_10"
+ android:valueTo="@color/gray_60"
+ android:valueType="colorType" />
+ </aapt:attr>
+ </target>
+ <target android:name="ic_play">
+ <aapt:attr name="android:animation">
+ <set>
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:propertyName="translateX"
+ android:startOffset="100"
+ android:valueFrom="8"
+ android:valueTo="0"
+ android:valueType="floatType" />
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:propertyName="scaleX"
+ android:startOffset="100"
+ android:valueFrom="0.5"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:propertyName="scaleY"
+ android:startOffset="100"
+ android:valueFrom="0.5"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="play">
+ <aapt:attr name="android:animation">
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/linear_interpolator"
+ android:propertyName="fillAlpha"
+ android:startOffset="100"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </aapt:attr>
+ </target>
+ <target android:name="ic_pause">
+ <aapt:attr name="android:animation">
+ <set>
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/accelerate_interpolator"
+ android:propertyName="translateX"
+ android:valueFrom="0"
+ android:valueTo="-8"
+ android:valueType="floatType" />
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/accelerate_interpolator"
+ android:propertyName="scaleX"
+ android:valueFrom="1"
+ android:valueTo="0.5"
+ android:valueType="floatType" />
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/accelerate_interpolator"
+ android:propertyName="scaleY"
+ android:valueFrom="1"
+ android:valueTo="0.5"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="pause">
+ <aapt:attr name="android:animation">
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/linear_interpolator"
+ android:propertyName="fillAlpha"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType" />
+ </aapt:attr>
+ </target>
+</animated-vector>
diff --git a/app/src/main/res/drawable/avd_video_recording_resume.xml b/app/src/main/res/drawable/avd_video_recording_resume.xml
new file mode 100644
index 0000000..0353ae7
--- /dev/null
+++ b/app/src/main/res/drawable/avd_video_recording_resume.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ SPDX-FileCopyrightText: 2022 The LineageOS Project
+ SPDX-License-Identifier: Apache-2.0
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:name="vector"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="32"
+ android:viewportHeight="32">
+ <path
+ android:name="backplate"
+ android:fillColor="@color/gray_60"
+ android:pathData="M 16 1 C 12.023 1 8.205 2.581 5.393 5.393 C 2.581 8.205 1 12.023 1 16 C 1 19.977 2.581 23.795 5.393 26.607 C 8.205 29.419 12.023 31 16 31 C 19.976 31 23.794 29.419 26.606 26.607 C 29.418 23.795 31 19.977 31 16 C 31 12.023 29.418 8.205 26.606 5.393 C 23.794 2.581 19.976 1 16 1 Z"
+ android:strokeWidth="2"
+ android:strokeColor="@color/white" />
+ <group
+ android:name="ic_pause"
+ android:pivotX="16"
+ android:pivotY="16"
+ android:scaleX="0.5"
+ android:scaleY="0.5"
+ android:translateX="-8">
+ <path
+ android:name="pause"
+ android:fillAlpha="0"
+ android:fillColor="@color/gray_60"
+ android:pathData="M 14 9 L 10 9 L 10 23 L 14 23 L 14 9 Z M 22 9 L 18 9 L 18 23 L 22 23 L 22 9 Z" />
+ </group>
+ <group
+ android:name="ic_play"
+ android:pivotX="16"
+ android:pivotY="16">
+ <path
+ android:name="play"
+ android:fillColor="@color/white"
+ android:pathData="M 11.5 9 L 22.5 16 L 11.5 23 L 11.5 9 Z" />
+ </group>
+ </vector>
+ </aapt:attr>
+ <target android:name="backplate">
+ <aapt:attr name="android:animation">
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/linear_interpolator"
+ android:propertyName="fillColor"
+ android:startOffset="100"
+ android:valueFrom="@color/gray_60"
+ android:valueTo="@color/gray_10"
+ android:valueType="colorType" />
+ </aapt:attr>
+ </target>
+ <target android:name="ic_play">
+ <aapt:attr name="android:animation">
+ <set>
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/accelerate_interpolator"
+ android:propertyName="translateX"
+ android:valueFrom="0"
+ android:valueTo="8"
+ android:valueType="floatType" />
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/accelerate_interpolator"
+ android:propertyName="scaleX"
+ android:valueFrom="1"
+ android:valueTo="0.5"
+ android:valueType="floatType" />
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/accelerate_interpolator"
+ android:propertyName="scaleY"
+ android:valueFrom="1"
+ android:valueTo="0.5"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="play">
+ <aapt:attr name="android:animation">
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/linear_interpolator"
+ android:propertyName="fillAlpha"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType" />
+ </aapt:attr>
+ </target>
+ <target android:name="ic_pause">
+ <aapt:attr name="android:animation">
+ <set>
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:propertyName="translateX"
+ android:startOffset="100"
+ android:valueFrom="-8"
+ android:valueTo="0"
+ android:valueType="floatType" />
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:propertyName="scaleX"
+ android:startOffset="100"
+ android:valueFrom="0.5"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:propertyName="scaleY"
+ android:startOffset="100"
+ android:valueFrom="0.5"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="pause">
+ <aapt:attr name="android:animation">
+ <objectAnimator
+ android:duration="200"
+ android:interpolator="@android:anim/linear_interpolator"
+ android:propertyName="fillAlpha"
+ android:startOffset="100"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </aapt:attr>
+ </target>
+</animated-vector>
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index d235c16..674fdd6 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -262,6 +262,19 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
+
+ <ImageButton
+ android:id="@+id/videoRecordingStateButton"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:background="@null"
+ android:contentDescription="@string/video_recording_state_button_description"
+ android:src="@drawable/avd_video_recording_pause"
+ android:visibility="gone"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="@+id/flipCameraButton"
+ app:layout_constraintStart_toStartOf="@+id/flipCameraButton"
+ app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 61b2e71..2740b6e 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -17,6 +17,7 @@
<string name="torch_button_description">Torch</string>
<string name="video_mode_button_description">Switch to video mode</string>
<string name="video_quality_button_description">Video quality</string>
+ <string name="video_recording_state_button_description">Pause/resume video recording</string>
<!-- Selector chip -->
<string name="selector_photo">PHOTO</string>