Aperture: Move video quality setting to top bar

Change-Id: Ieb37d8f85294cb50dc2a365bc3298d40106fc7ce
diff --git a/app/src/main/java/org/lineageos/aperture/MainActivity.kt b/app/src/main/java/org/lineageos/aperture/MainActivity.kt
index 1280e9d..b619f8d 100644
--- a/app/src/main/java/org/lineageos/aperture/MainActivity.kt
+++ b/app/src/main/java/org/lineageos/aperture/MainActivity.kt
@@ -45,6 +45,7 @@
 import androidx.camera.extensions.ExtensionMode
 import androidx.camera.extensions.ExtensionsManager
 import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.video.Quality
 import androidx.camera.video.Recording
 import androidx.camera.video.VideoRecordEvent
 import androidx.camera.view.CameraController
@@ -103,6 +104,7 @@
     private val timerChip by lazy { findViewById<Chip>(R.id.timerChip) }
     private val torchButton by lazy { findViewById<ImageButton>(R.id.torchButton) }
     private val videoModeButton by lazy { findViewById<MaterialButton>(R.id.videoModeButton) }
+    private val videoQualityButton by lazy { findViewById<ToggleButton>(R.id.videoQualityButton) }
     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) }
@@ -136,6 +138,8 @@
 
     private var viewFinderTouchEvent: MotionEvent? = null
 
+    private val videoQuality: Quality
+        get() = sharedPreferences.videoQuality
     private var recording: Recording? = null
     private val recordingLock = Mutex()
     private var recordingTime = 0L
@@ -224,6 +228,7 @@
 
         // Set top bar button callbacks
         aspectRatioButton.setOnClickListener { cycleAspectRatio() }
+        videoQualityButton.setOnClickListener { cycleVideoQuality() }
         effectButton.setOnClickListener { cyclePhotoEffects() }
         gridButton.setOnClickListener { cycleGridMode() }
         timerButton.setOnClickListener { toggleTimerMode() }
@@ -558,6 +563,10 @@
             }
         }
 
+        // Get a stable reference to CameraInfo
+        // We can hardcode the first one in the filter as long as we use DEFAULT_*_CAMERA
+        camera = PhysicalCamera(cameraSelector.filter(cameraProvider.availableCameraInfos).first())
+
         // Get the supported vendor extensions for the given camera selector
         supportedExtensionModes = extensionsManager.getSupportedModes(cameraSelector)
 
@@ -571,6 +580,11 @@
         aspectRatio = sharedPreferences.aspectRatio
         val outputSize = CameraController.OutputSize(aspectRatio)
 
+        // Fallback to highest supported video quality
+        if (!camera.supportedVideoQualities.contains(sharedPreferences.videoQuality)) {
+            sharedPreferences.videoQuality = camera.supportedVideoQualities.first()
+        }
+
         // Initialize the use case we want and set its properties
         val cameraUseCases = when (cameraMode) {
             CameraMode.QR -> {
@@ -584,7 +598,7 @@
             }
             CameraMode.VIDEO -> {
                 cameraController.videoCaptureTargetQuality = null // FIXME: video preview restart
-                cameraController.videoCaptureTargetQuality = sharedPreferences.videoQuality
+                cameraController.videoCaptureTargetQuality = videoQuality
                 CameraController.VIDEO_CAPTURE
             }
         }
@@ -622,10 +636,6 @@
         // Bind camera controller to lifecycle
         cameraController.bindToLifecycle(this)
 
-        // Get a stable reference to CameraInfo
-        // We can hardcode the first one in the filter as long as we use DEFAULT_*_CAMERA
-        camera = PhysicalCamera(cameraSelector.filter(cameraProvider.availableCameraInfos)[0])
-
         // Restore settings that can be set on the fly
         setGridMode(sharedPreferences.lastGridMode)
         setFlashMode(sharedPreferences.photoFlashMode)
@@ -635,6 +645,7 @@
         updateCameraModeButtons()
         updateTimerModeIcon()
         updateAspectRatioIcon()
+        updateVideoQualityIcon()
         updatePhotoEffectIcon()
         updateGridIcon()
         updateTorchModeIcon()
@@ -717,6 +728,27 @@
         bindCameraUseCases()
     }
 
+    private fun cycleVideoQuality() {
+        if (!canRestartCamera()) {
+            return
+        }
+
+        val newVideoQuality = if (videoQuality == camera.supportedVideoQualities.first()) {
+            camera.supportedVideoQualities.last()
+        } else {
+            val index = camera.supportedVideoQualities.indexOf(videoQuality)
+            camera.supportedVideoQualities[maxOf(0, index - 1)]
+        }
+
+        if (newVideoQuality == videoQuality) {
+            return
+        }
+
+        sharedPreferences.videoQuality = newVideoQuality
+
+        bindCameraUseCases()
+    }
+
     /**
      * Update the grid button icon based on the value set in grid view
      */
@@ -789,6 +821,17 @@
         }
     }
 
+    private fun updateVideoQualityIcon() {
+        videoQualityButton.isVisible = cameraMode == CameraMode.VIDEO
+        videoQualityButton.text = when (videoQuality) {
+            Quality.SD -> "SD"
+            Quality.HD -> "HD"
+            Quality.FHD -> "FHD"
+            Quality.UHD -> "UHD"
+            else -> throw Exception("Unknown video quality $videoQuality")
+        }
+    }
+
     /**
      * Update the torch mode button icon based on the value set in camera
      */
diff --git a/app/src/main/java/org/lineageos/aperture/SharedPreferencesExt.kt b/app/src/main/java/org/lineageos/aperture/SharedPreferencesExt.kt
index 2a0bcb6..14de37b 100644
--- a/app/src/main/java/org/lineageos/aperture/SharedPreferencesExt.kt
+++ b/app/src/main/java/org/lineageos/aperture/SharedPreferencesExt.kt
@@ -188,29 +188,25 @@
 
 // Video prefs
 private const val VIDEO_QUALITY_KEY = "video_quality"
-private const val VIDEO_QUALITY_DEFAULT = "highest"
+private const val VIDEO_QUALITY_DEFAULT = "fhd"
 
 internal var SharedPreferences.videoQuality: Quality
     get() = when (getString(VIDEO_QUALITY_KEY, VIDEO_QUALITY_DEFAULT)) {
-        "lowest" -> Quality.LOWEST
         "sd" -> Quality.SD
         "hd" -> Quality.HD
         "fhd" -> Quality.FHD
         "uhd" -> Quality.UHD
-        "highest" -> Quality.HIGHEST
-        // Default to highest
-        else -> Quality.HIGHEST
+        // Default to fhd
+        else -> Quality.FHD
     }
     set(value) = edit {
         putString(
             VIDEO_QUALITY_KEY, when (value) {
-                Quality.LOWEST -> "lowest"
                 Quality.SD -> "sd"
                 Quality.HD -> "hd"
                 Quality.FHD -> "fhd"
                 Quality.UHD -> "uhd"
-                Quality.HIGHEST -> "highest"
-                // Default to highest
+                // Default to fhd
                 else -> VIDEO_QUALITY_DEFAULT
             }
         )
diff --git a/app/src/main/java/org/lineageos/aperture/utils/PhysicalCamera.kt b/app/src/main/java/org/lineageos/aperture/utils/PhysicalCamera.kt
index f493a1a..f100a41 100644
--- a/app/src/main/java/org/lineageos/aperture/utils/PhysicalCamera.kt
+++ b/app/src/main/java/org/lineageos/aperture/utils/PhysicalCamera.kt
@@ -9,6 +9,7 @@
 import android.hardware.camera2.CameraCharacteristics
 import androidx.camera.camera2.interop.Camera2CameraInfo
 import androidx.camera.core.CameraInfo
+import androidx.camera.video.QualitySelector
 
 /**
  * Class representing a physical device camera
@@ -40,4 +41,9 @@
      * Flash is available or not
      */
     val hasFlashUnit = cameraInfo.hasFlashUnit()
+
+    /**
+     * Supported video qualities
+     */
+    val supportedVideoQualities = QualitySelector.getSupportedQualities(cameraInfo)
 }
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 83800ff..287d1a4 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -42,11 +42,24 @@
             android:background="?attr/selectableItemBackgroundBorderless"
             android:contentDescription="@string/aspect_ratio_button_description"
             app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintEnd_toStartOf="@+id/effectButton"
+            app:layout_constraintEnd_toStartOf="@+id/videoQualityButton"
             app:layout_constraintHorizontal_bias="0.5"
             app:layout_constraintStart_toEndOf="@+id/timerButton"
             app:layout_constraintTop_toTopOf="parent" />
 
+        <ToggleButton
+            android:id="@+id/videoQualityButton"
+            style="@style/ApertureTopBarButton"
+            android:layout_width="@dimen/top_view_buttons_size"
+            android:layout_height="@dimen/top_view_buttons_size"
+            android:background="?attr/selectableItemBackgroundBorderless"
+            android:contentDescription="@string/video_quality_button_description"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/effectButton"
+            app:layout_constraintHorizontal_bias="0.5"
+            app:layout_constraintStart_toEndOf="@+id/aspectRatioButton"
+            app:layout_constraintTop_toTopOf="parent" />
+
         <ImageButton
             android:id="@+id/effectButton"
             style="@style/ApertureTopBarButton"
@@ -58,7 +71,7 @@
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toStartOf="@+id/gridButton"
             app:layout_constraintHorizontal_bias="0.5"
-            app:layout_constraintStart_toEndOf="@+id/aspectRatioButton"
+            app:layout_constraintStart_toEndOf="@+id/videoQualityButton"
             app:layout_constraintTop_toTopOf="parent" />
 
         <ImageButton
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index c2a47b1..f80a8f7 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -12,25 +12,6 @@
         <item>zero_shutter_lag</item>
     </string-array>
 
-    <!-- Video quality Preference -->
-    <string-array name="video_quality_entries">
-        <item>@string/video_quality_lowest</item>
-        <item>SD</item>
-        <item>HD</item>
-        <item>FHD</item>
-        <item>UHD</item>
-        <item>@string/video_quality_highest</item>
-    </string-array>
-
-    <string-array name="video_quality_values">
-        <item>lowest</item>
-        <item>sd</item>
-        <item>hd</item>
-        <item>fhd</item>
-        <item>uhd</item>
-        <item>highest</item>
-    </string-array>
-
     <string-array name="qr_bottom_sheet_dialog_types">
         <item>@string/qr_type_bytes</item>
         <item>@string/qr_type_text</item>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d1c2d64..31cb759 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -4,6 +4,7 @@
     <!-- Button descriptions -->
     <string name="timer_button_description">Timer</string>
     <string name="aspect_ratio_button_description">Aspect ratio</string>
+    <string name="video_quality_button_description">Video quality</string>
     <string name="effect_button_description">Effect</string>
     <string name="grid_button_description">Grid</string>
     <string name="torch_button_description">Torch</string>
@@ -46,7 +47,6 @@
     <!-- Preference Titles -->
     <string name="general_header">General</string>
     <string name="photos_header">Photos</string>
-    <string name="videos_header">Videos</string>
 
     <!-- General Preferences -->
     <string name="bright_screen_title">Bright screen</string>
@@ -62,9 +62,4 @@
     <string name="photo_capture_mode_maximize_quality">Maximize quality</string>
     <string name="photo_capture_mode_minimize_latency">Minimize latency</string>
     <string name="photo_capture_mode_zsl">Zero shutter lag (experimental)</string>
-
-    <!-- Videos Preferences -->
-    <string name="video_quality_title">Video quality</string>
-    <string name="video_quality_lowest">Lowest</string>
-    <string name="video_quality_highest">Highest</string>
 </resources>
\ No newline at end of file
diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml
index f1cec37..e5bbbc9 100644
--- a/app/src/main/res/xml/root_preferences.xml
+++ b/app/src/main/res/xml/root_preferences.xml
@@ -42,19 +42,4 @@
 
     </PreferenceCategory>
 
-    <PreferenceCategory
-        app:iconSpaceReserved="false"
-        app:title="@string/videos_header">
-
-        <ListPreference
-            app:defaultValue="highest"
-            app:entries="@array/video_quality_entries"
-            app:entryValues="@array/video_quality_values"
-            app:iconSpaceReserved="false"
-            app:key="video_quality"
-            app:title="@string/video_quality_title"
-            app:useSimpleSummaryProvider="true" />
-
-    </PreferenceCategory>
-
 </PreferenceScreen>
\ No newline at end of file