Glimpse: Support waterfall display cutout

Test: Use the app with the waterfall cutout in developer settings
Change-Id: Ib056f2e8fd798d0854a9b02ce88dd5459cf300df
diff --git a/app/src/main/java/org/lineageos/glimpse/PickerActivity.kt b/app/src/main/java/org/lineageos/glimpse/PickerActivity.kt
index 3460d11..b4d9e66 100644
--- a/app/src/main/java/org/lineageos/glimpse/PickerActivity.kt
+++ b/app/src/main/java/org/lineageos/glimpse/PickerActivity.kt
@@ -8,9 +8,14 @@
 import android.content.Intent
 import android.os.Bundle
 import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
 import android.widget.Toast
 import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.ViewCompat
 import androidx.core.view.WindowCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.updateLayoutParams
 import com.google.android.material.appbar.AppBarLayout
 import com.google.android.material.appbar.MaterialToolbar
 import com.google.android.material.shape.MaterialShapeDrawable
@@ -20,6 +25,7 @@
 class PickerActivity : AppCompatActivity(R.layout.activity_picker) {
     // Views
     private val appBarLayout by lazy { findViewById<AppBarLayout>(R.id.appBarLayout)!! }
+    private val contentView by lazy { findViewById<View>(android.R.id.content)!! }
     private val toolbar by lazy { findViewById<MaterialToolbar>(R.id.toolbar)!! }
 
     override fun onCreate(savedInstanceState: Bundle?) {
@@ -36,6 +42,19 @@
             setDisplayShowHomeEnabled(true)
         }
 
+        ViewCompat.setOnApplyWindowInsetsListener(contentView) { _, windowInsets ->
+            val insets = windowInsets.getInsets(
+                WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
+            )
+
+            toolbar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
+                leftMargin = insets.left
+                rightMargin = insets.right
+            }
+
+            windowInsets
+        }
+
         // Parse intent
         if (intent.action !in supportedIntentActions) {
             Toast.makeText(
diff --git a/app/src/main/java/org/lineageos/glimpse/SetWallpaperActivity.kt b/app/src/main/java/org/lineageos/glimpse/SetWallpaperActivity.kt
index 7443480..bf77238 100644
--- a/app/src/main/java/org/lineageos/glimpse/SetWallpaperActivity.kt
+++ b/app/src/main/java/org/lineageos/glimpse/SetWallpaperActivity.kt
@@ -8,14 +8,21 @@
 import android.app.WallpaperManager
 import android.net.Uri
 import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
 import android.widget.ImageView
 import android.widget.Toast
 import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.updateLayoutParams
 import com.google.android.material.button.MaterialButton
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 
 class SetWallpaperActivity : AppCompatActivity(R.layout.activity_set_wallpaper) {
     // Views
+    private val contentView by lazy { findViewById<View>(android.R.id.content)!! }
     private val wallpaperImageView by lazy { findViewById<ImageView>(R.id.wallpaperImageView)!! }
     private val setWallpaperButton by lazy { findViewById<MaterialButton>(R.id.setWallpaperButton)!! }
 
@@ -25,6 +32,21 @@
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
+        // Setup edge-to-edge
+        WindowCompat.setDecorFitsSystemWindows(window, false)
+
+        ViewCompat.setOnApplyWindowInsetsListener(contentView) { _, windowInsets ->
+            val insets = windowInsets.getInsets(
+                WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
+            )
+
+            setWallpaperButton.updateLayoutParams<ViewGroup.MarginLayoutParams> {
+                bottomMargin = insets.bottom
+            }
+
+            windowInsets
+        }
+
         // Load wallpaper from intent
         val wallpaperUri = intent.data ?: run {
             Toast.makeText(this, R.string.intent_media_not_found, Toast.LENGTH_LONG).show()
diff --git a/app/src/main/java/org/lineageos/glimpse/ViewActivity.kt b/app/src/main/java/org/lineageos/glimpse/ViewActivity.kt
index 9ddb9f3..682aff8 100644
--- a/app/src/main/java/org/lineageos/glimpse/ViewActivity.kt
+++ b/app/src/main/java/org/lineageos/glimpse/ViewActivity.kt
@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2023 The LineageOS Project
+ * SPDX-FileCopyrightText: 2023-2024 The LineageOS Project
  * SPDX-License-Identifier: Apache-2.0
  */
 
@@ -296,7 +296,9 @@
         }
 
         ViewCompat.setOnApplyWindowInsetsListener(contentView) { _, windowInsets ->
-            val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
+            val insets = windowInsets.getInsets(
+                WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
+            )
 
             // Avoid updating the sheets height when they're hidden.
             // Once the system bars will be made visible again, this function
diff --git a/app/src/main/java/org/lineageos/glimpse/fragments/AlbumViewerFragment.kt b/app/src/main/java/org/lineageos/glimpse/fragments/AlbumViewerFragment.kt
index 7b16907..461f0eb 100644
--- a/app/src/main/java/org/lineageos/glimpse/fragments/AlbumViewerFragment.kt
+++ b/app/src/main/java/org/lineageos/glimpse/fragments/AlbumViewerFragment.kt
@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2023 The LineageOS Project
+ * SPDX-FileCopyrightText: 2023-2024 The LineageOS Project
  * SPDX-License-Identifier: Apache-2.0
  */
 
@@ -332,7 +332,14 @@
         recyclerView.adapter = thumbnailAdapter
 
         ViewCompat.setOnApplyWindowInsetsListener(view) { _, windowInsets ->
-            val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
+            val insets = windowInsets.getInsets(
+                WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
+            )
+
+            toolbar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
+                leftMargin = insets.left
+                rightMargin = insets.right
+            }
 
             recyclerView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
                 leftMargin = insets.left
diff --git a/app/src/main/java/org/lineageos/glimpse/fragments/AlbumsFragment.kt b/app/src/main/java/org/lineageos/glimpse/fragments/AlbumsFragment.kt
index 1cdf2ae..b3b6bd0 100644
--- a/app/src/main/java/org/lineageos/glimpse/fragments/AlbumsFragment.kt
+++ b/app/src/main/java/org/lineageos/glimpse/fragments/AlbumsFragment.kt
@@ -23,6 +23,7 @@
 import androidx.navigation.fragment.findNavController
 import androidx.recyclerview.widget.RecyclerView
 import com.google.android.material.appbar.AppBarLayout
+import com.google.android.material.appbar.MaterialToolbar
 import com.google.android.material.shape.MaterialShapeDrawable
 import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.launch
@@ -50,6 +51,7 @@
     private val albumsRecyclerView by getViewProperty<RecyclerView>(R.id.albumsRecyclerView)
     private val appBarLayout by getViewProperty<AppBarLayout>(R.id.appBarLayout)
     private val noMediaLinearLayout by getViewProperty<LinearLayout>(R.id.noMediaLinearLayout)
+    private val toolbar by getViewProperty<MaterialToolbar>(R.id.toolbar)
 
     // Fragments
     private val parentNavController by lazy {
@@ -98,7 +100,14 @@
         albumsRecyclerView.adapter = albumThumbnailAdapter
 
         ViewCompat.setOnApplyWindowInsetsListener(view) { _, windowInsets ->
-            val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
+            val insets = windowInsets.getInsets(
+                WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
+            )
+
+            toolbar.updateLayoutParams<MarginLayoutParams> {
+                leftMargin = insets.left
+                rightMargin = insets.right
+            }
 
             albumsRecyclerView.updateLayoutParams<MarginLayoutParams> {
                 leftMargin = insets.left
diff --git a/app/src/main/java/org/lineageos/glimpse/fragments/SearchFragment.kt b/app/src/main/java/org/lineageos/glimpse/fragments/SearchFragment.kt
index 416a502..327a756 100644
--- a/app/src/main/java/org/lineageos/glimpse/fragments/SearchFragment.kt
+++ b/app/src/main/java/org/lineageos/glimpse/fragments/SearchFragment.kt
@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2023 The LineageOS Project
+ * SPDX-FileCopyrightText: 2023-2024 The LineageOS Project
  * SPDX-License-Identifier: Apache-2.0
  */
 
@@ -7,10 +7,16 @@
 
 import android.os.Bundle
 import android.view.View
+import android.view.ViewGroup
 import androidx.core.os.bundleOf
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.updateLayoutParams
+import androidx.core.widget.NestedScrollView
 import androidx.fragment.app.Fragment
 import androidx.navigation.fragment.findNavController
 import com.google.android.material.appbar.AppBarLayout
+import com.google.android.material.search.SearchBar
 import com.google.android.material.shape.MaterialShapeDrawable
 import org.lineageos.glimpse.R
 import org.lineageos.glimpse.ext.getViewProperty
@@ -27,6 +33,8 @@
     private val appBarLayout by getViewProperty<AppBarLayout>(R.id.appBarLayout)
     private val favoritesAlbumListItem by getViewProperty<ListItem>(R.id.favoritesAlbumListItem)
     private val photosAlbumListItem by getViewProperty<ListItem>(R.id.photosAlbumListItem)
+    private val searchNestedScrollView by getViewProperty<NestedScrollView>(R.id.searchNestedScrollView)
+    private val searchBar by getViewProperty<SearchBar>(R.id.searchBar)
     private val trashAlbumListItem by getViewProperty<ListItem>(R.id.trashAlbumListItem)
     private val videosAlbumListItem by getViewProperty<ListItem>(R.id.videosAlbumListItem)
 
@@ -42,6 +50,24 @@
 
         appBarLayout.statusBarForeground = MaterialShapeDrawable.createWithElevationOverlay(context)
 
+        ViewCompat.setOnApplyWindowInsetsListener(view) { _, windowInsets ->
+            val insets = windowInsets.getInsets(
+                WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
+            )
+
+            searchBar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
+                leftMargin = insets.left
+                rightMargin = insets.right
+            }
+
+            searchNestedScrollView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
+                leftMargin = insets.left
+                rightMargin = insets.right
+            }
+
+            windowInsets
+        }
+
         photosAlbumListItem.setOnClickListener {
             openAlbum(MediaStoreBuckets.MEDIA_STORE_BUCKET_PHOTOS)
         }
diff --git a/app/src/main/java/org/lineageos/glimpse/fragments/picker/AlbumSelectorFragment.kt b/app/src/main/java/org/lineageos/glimpse/fragments/picker/AlbumSelectorFragment.kt
index e98196d..91ed55e 100644
--- a/app/src/main/java/org/lineageos/glimpse/fragments/picker/AlbumSelectorFragment.kt
+++ b/app/src/main/java/org/lineageos/glimpse/fragments/picker/AlbumSelectorFragment.kt
@@ -88,7 +88,9 @@
         albumsRecyclerView.adapter = albumThumbnailAdapter
 
         ViewCompat.setOnApplyWindowInsetsListener(view) { _, windowInsets ->
-            val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
+            val insets = windowInsets.getInsets(
+                WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
+            )
 
             albumsRecyclerView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
                 leftMargin = insets.left
diff --git a/app/src/main/java/org/lineageos/glimpse/fragments/picker/MediaSelectorFragment.kt b/app/src/main/java/org/lineageos/glimpse/fragments/picker/MediaSelectorFragment.kt
index d87b829..690455d 100644
--- a/app/src/main/java/org/lineageos/glimpse/fragments/picker/MediaSelectorFragment.kt
+++ b/app/src/main/java/org/lineageos/glimpse/fragments/picker/MediaSelectorFragment.kt
@@ -184,7 +184,9 @@
         mediasRecyclerView.adapter = thumbnailAdapter
 
         ViewCompat.setOnApplyWindowInsetsListener(view) { _, windowInsets ->
-            val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
+            val insets = windowInsets.getInsets(
+                WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
+            )
 
             mediasRecyclerView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
                 leftMargin = insets.left
diff --git a/app/src/main/java/org/lineageos/glimpse/ui/MediaInfoBottomSheetDialog.kt b/app/src/main/java/org/lineageos/glimpse/ui/MediaInfoBottomSheetDialog.kt
index e374a54..39b5454 100644
--- a/app/src/main/java/org/lineageos/glimpse/ui/MediaInfoBottomSheetDialog.kt
+++ b/app/src/main/java/org/lineageos/glimpse/ui/MediaInfoBottomSheetDialog.kt
@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2023 The LineageOS Project
+ * SPDX-FileCopyrightText: 2023-2024 The LineageOS Project
  * SPDX-License-Identifier: Apache-2.0
  */
 
@@ -13,13 +13,18 @@
 import android.net.Uri
 import android.os.Build
 import android.text.InputType
+import android.view.View
+import android.view.ViewGroup
 import android.widget.EditText
 import android.widget.TextView
 import android.widget.Toast
 import androidx.activity.result.contract.ActivityResultContracts
 import androidx.appcompat.app.AppCompatActivity
 import androidx.core.content.res.ResourcesCompat
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
 import androidx.core.view.isVisible
+import androidx.core.view.updateLayoutParams
 import androidx.exifinterface.media.ExifInterface
 import com.google.android.material.bottomsheet.BottomSheetDialog
 import kotlinx.coroutines.CoroutineScope
@@ -42,6 +47,7 @@
     // Views
     private val artistInfoListItem by lazy { findViewById<ListItem>(R.id.artistInfoListItem)!! }
     private val cameraInfoListItem by lazy { findViewById<ListItem>(R.id.cameraInfoListItem)!! }
+    private val contentView by lazy { findViewById<View>(android.R.id.content)!! }
     private val dateTextView by lazy { findViewById<TextView>(R.id.dateTextView)!! }
     private val descriptionEditText by lazy { findViewById<EditText>(R.id.descriptionEditText)!! }
     private val locationInfoListItem by lazy { findViewById<ListItem>(R.id.locationInfoListItem)!! }
@@ -61,6 +67,19 @@
     init {
         setContentView(R.layout.media_info_bottom_sheet_dialog)
 
+        ViewCompat.setOnApplyWindowInsetsListener(contentView) { _, windowInsets ->
+            val insets = windowInsets.getInsets(
+                WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
+            )
+
+            contentView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
+                leftMargin = insets.left
+                rightMargin = insets.right
+            }
+
+            windowInsets
+        }
+
         descriptionEditText.setOnEditorActionListener { _, _, _ ->
             callbacks.onEditDescription(media, descriptionEditText.text.toString().trim())
 
diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml
index 1ea0bfd..fe03199 100644
--- a/app/src/main/res/layout/fragment_search.xml
+++ b/app/src/main/res/layout/fragment_search.xml
@@ -13,12 +13,15 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:fitsSystemWindows="true"
+        android:paddingHorizontal="16dp"
         app:liftOnScrollTargetViewId="@+id/searchNestedScrollView">
 
         <com.google.android.material.search.SearchBar
             android:id="@+id/searchBar"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
+            android:layout_height="wrap_content"
+            android:layout_marginVertical="16dp"
+            app:defaultMarginsEnabled="false" />
 
     </com.google.android.material.appbar.AppBarLayout>
 
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 4f300e1..cf48d2a 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -8,7 +8,7 @@
     <style name="Theme.Glimpse" parent="Theme.Material3.DayNight.NoActionBar">
         <item name="android:navigationBarColor">@android:color/transparent</item>
         <item name="android:statusBarColor">@android:color/transparent</item>
-        <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
+        <item name="android:windowLayoutInDisplayCutoutMode">always</item>
         <item name="android:windowLightStatusBar">?attr/isLightTheme</item>
         <item name="windowActionModeOverlay">true</item>
     </style>
@@ -40,7 +40,7 @@
     <style name="Theme.Glimpse.MediaViewer" parent="Theme.Material3.Dark.NoActionBar">
         <item name="android:navigationBarColor">@android:color/transparent</item>
         <item name="android:statusBarColor">@android:color/transparent</item>
-        <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
+        <item name="android:windowLayoutInDisplayCutoutMode">always</item>
         <item name="android:windowLightStatusBar">?attr/isLightTheme</item>
     </style>