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>