Aperture: Get rid of null assertions in CameraManager

Change-Id: I6422783fb0daadf740dde4ace0bd1b8716d6996a
diff --git a/app/src/main/java/org/lineageos/aperture/camera/CameraManager.kt b/app/src/main/java/org/lineageos/aperture/camera/CameraManager.kt
index 79329a9..f394d28 100644
--- a/app/src/main/java/org/lineageos/aperture/camera/CameraManager.kt
+++ b/app/src/main/java/org/lineageos/aperture/camera/CameraManager.kt
@@ -26,7 +26,8 @@
 @androidx.camera.camera2.interop.ExperimentalCamera2Interop
 class CameraManager(context: Context) {
     private val cameraProvider = ProcessCameraProvider.getInstance(context).get()
-    val extensionsManager = ExtensionsManager.getInstanceAsync(context, cameraProvider).get()!!
+    val extensionsManager: ExtensionsManager =
+        ExtensionsManager.getInstanceAsync(context, cameraProvider).get()
     val cameraController = LifecycleCameraController(context)
     val cameraExecutor: ExecutorService = Executors.newSingleThreadExecutor()
 
@@ -56,13 +57,11 @@
                                 else -> null
                             }
                         }.distinct().forEach { quality ->
-                            if (!this.containsKey(cameraId)) {
-                                this[cameraId] = mutableMapOf()
+                            getOrCreate(cameraId).apply {
+                                getOrCreate(quality).apply {
+                                    putAll(frameRates)
+                                }
                             }
-                            if (!this[cameraId]!!.containsKey(quality)) {
-                                this[cameraId]!![quality] = mutableMapOf()
-                            }
-                            this[cameraId]!![quality]!!.putAll(frameRates)
                         }
                     }
                 }
@@ -94,10 +93,9 @@
                     val approximateZoomRatio = it[i + 1].toFloat()
                     val exactZoomRatio = it[i + 2].toFloat()
 
-                    if (!this.containsKey(cameraId)) {
-                        this[cameraId] = mutableMapOf()
+                    getOrCreate(cameraId).apply {
+                        this[approximateZoomRatio] = exactZoomRatio
                     }
-                    this[cameraId]!![approximateZoomRatio] = exactZoomRatio
                 }
             }
         }.map { a ->
diff --git a/app/src/main/java/org/lineageos/aperture/ext/MutableList.kt b/app/src/main/java/org/lineageos/aperture/ext/MutableList.kt
new file mode 100644
index 0000000..865a6cb
--- /dev/null
+++ b/app/src/main/java/org/lineageos/aperture/ext/MutableList.kt
@@ -0,0 +1,33 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The LineageOS Project
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.lineageos.aperture.ext
+
+/**
+ * Returns the value for the given [index] if the value is present and not `null`.
+ * Otherwise, calls the [defaultValue] function,
+ * puts its result into the list under the given index and returns the call result.
+ *
+ * Note that the operation is not guaranteed to be atomic if the map is being modified concurrently.
+ */
+inline fun <E> MutableList<E>.getOrPut(index: Int, defaultValue: () -> E) =
+    get(index) ?: defaultValue().also {
+        set(index, it)
+    }
+
+inline fun <reified E : MutableList<ListE>, ListE> MutableList<E>.getOrCreate(index: Int) =
+    getOrPut(index) {
+        mutableListOf<ListE>() as E // idk why this is needed
+    }
+
+inline fun <reified E : MutableMap<MapK, MapV>, MapK, MapV> MutableList<E>.getOrCreate(index: Int) =
+    getOrPut(index) {
+        mutableMapOf<MapK, MapV>() as E // idk why this is needed
+    }
+
+inline fun <reified E : MutableSet<SetE>, SetE> MutableList<E>.getOrCreate(index: Int) =
+    getOrPut(index) {
+        mutableSetOf<SetE>() as E // idk why this is needed
+    }
diff --git a/app/src/main/java/org/lineageos/aperture/ext/MutableMap.kt b/app/src/main/java/org/lineageos/aperture/ext/MutableMap.kt
new file mode 100644
index 0000000..70e9389
--- /dev/null
+++ b/app/src/main/java/org/lineageos/aperture/ext/MutableMap.kt
@@ -0,0 +1,22 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The LineageOS Project
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.lineageos.aperture.ext
+
+inline fun <K, reified V : MutableList<ListE>, ListE> MutableMap<K, V>.getOrCreate(key: K) =
+    getOrPut(key) {
+        mutableListOf<ListE>() as V // idk why this is needed
+    }
+
+inline fun <K, reified V : MutableMap<MapK, MapV>, MapK, MapV> MutableMap<K, V>.getOrCreate(
+    key: K
+) = getOrPut(key) {
+    mutableMapOf<MapK, MapV>() as V // idk why this is needed
+}
+
+inline fun <K, reified V : MutableSet<SetE>, SetE> MutableMap<K, V>.getOrCreate(key: K) =
+    getOrPut(key) {
+        mutableSetOf<SetE>() as V // idk why this is needed
+    }