From e5901fa9e2a16cc23c72076e98ff42fa0cfe8b04 Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Tue, 18 Jan 2022 19:51:06 -0700 Subject: [PATCH] playback: use gesture insets in playback layout When using gesture navigation, swipe up events might conflict with the slide up behavior of the playback layout. To fix this, inset the playback bar based on the gesture insets instead of the system bar insets. --- .../java/org/oxycblt/auxio/MainActivity.kt | 15 +++++--- .../home/FloatingActionButtonContainer.kt | 4 +-- .../home/fastscroll/FastScrollRecyclerView.kt | 4 +-- .../oxycblt/auxio/playback/PlaybackBarView.kt | 35 +++++++++++++++---- .../auxio/playback/PlaybackFragment.kt | 4 +-- .../oxycblt/auxio/playback/PlaybackLayout.kt | 35 ++++--------------- .../oxycblt/auxio/settings/AboutFragment.kt | 4 +-- .../auxio/settings/SettingsListFragment.kt | 4 +-- .../org/oxycblt/auxio/ui/EdgeAppBarLayout.kt | 4 +-- .../org/oxycblt/auxio/ui/EdgeRecyclerView.kt | 4 +-- .../java/org/oxycblt/auxio/util/ViewUtil.kt | 2 +- 11 files changed, 62 insertions(+), 53 deletions(-) diff --git a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt index b6321d07a..e4dd7d34f 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt @@ -37,7 +37,7 @@ import org.oxycblt.auxio.settings.SettingsManager import org.oxycblt.auxio.util.isNight import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.replaceInsetsCompat -import org.oxycblt.auxio.util.systemBarsCompat +import org.oxycblt.auxio.util.systemBarInsetsCompat /** * The single [AppCompatActivity] for Auxio. @@ -113,18 +113,25 @@ class MainActivity : AppCompatActivity() { private fun applyEdgeToEdgeWindow(binding: ViewBinding) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - // Do modern edge to edge, which happens to be around twice the size of the - // old way of doing things. Thanks android, very cool! logD("Doing R+ edge-to-edge.") window?.setDecorFitsSystemWindows(false) + // "Should we automatically acquire the insets we need and return them + // whenever the user wants them?" + // "Nah, let's make the user define what insets they want instead through + // a barely-documented API that is not brought up in a single tutorial!" + // "Great idea!" binding.root.setOnApplyWindowInsetsListener { _, insets -> WindowInsets.Builder() .setInsets( WindowInsets.Type.systemBars(), insets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()) ) + .setInsets( + WindowInsets.Type.systemGestures(), + insets.getInsetsIgnoringVisibility(WindowInsets.Type.systemGestures()) + ) .build() .applyLeftRightInsets(binding) } @@ -145,7 +152,7 @@ class MainActivity : AppCompatActivity() { } private fun WindowInsets.applyLeftRightInsets(binding: ViewBinding): WindowInsets { - val bars = systemBarsCompat + val bars = systemBarInsetsCompat binding.root.updatePadding( left = bars.left, diff --git a/app/src/main/java/org/oxycblt/auxio/home/FloatingActionButtonContainer.kt b/app/src/main/java/org/oxycblt/auxio/home/FloatingActionButtonContainer.kt index b73a2b371..863306dc9 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/FloatingActionButtonContainer.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/FloatingActionButtonContainer.kt @@ -23,7 +23,7 @@ import android.util.AttributeSet import android.view.WindowInsets import android.widget.FrameLayout import androidx.core.view.updatePadding -import org.oxycblt.auxio.util.systemBarsCompat +import org.oxycblt.auxio.util.systemBarInsetsCompat /** * A container for a FloatingActionButton that enables edge-to-edge support. @@ -43,7 +43,7 @@ class FloatingActionButtonContainer @JvmOverloads constructor( } override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets { - updatePadding(bottom = insets.systemBarsCompat.bottom) + updatePadding(bottom = insets.systemBarInsetsCompat.bottom) return insets } diff --git a/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt b/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt index 94696e469..74c9ed99d 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/fastscroll/FastScrollRecyclerView.kt @@ -44,7 +44,7 @@ import org.oxycblt.auxio.R import org.oxycblt.auxio.util.canScroll import org.oxycblt.auxio.util.resolveAttr import org.oxycblt.auxio.util.resolveDrawable -import org.oxycblt.auxio.util.systemBarsCompat +import org.oxycblt.auxio.util.systemBarInsetsCompat import kotlin.math.abs /** @@ -315,7 +315,7 @@ class FastScrollRecyclerView @JvmOverloads constructor( } override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets { - val bars = insets.systemBarsCompat + val bars = insets.systemBarInsetsCompat updatePadding( initialPadding.left, initialPadding.top, initialPadding.right, diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarView.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarView.kt index 350cb61ef..81599c23b 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarView.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarView.kt @@ -19,6 +19,7 @@ package org.oxycblt.auxio.playback import android.content.Context +import android.os.Build import android.util.AttributeSet import android.view.WindowInsets import androidx.constraintlayout.widget.ConstraintLayout @@ -31,7 +32,7 @@ import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.util.inflater import org.oxycblt.auxio.util.resolveAttr -import org.oxycblt.auxio.util.systemBarsCompat +import org.oxycblt.auxio.util.systemBarInsetsCompat /** * A view displaying the playback state in a compact manner. This is only meant to be used @@ -48,17 +49,39 @@ class PlaybackBarView @JvmOverloads constructor( id = R.id.playback_bar // Deliberately override the progress bar color [in a Lollipop-friendly way] so that - // we use colorSecondary instead of colorSurfaceVariant. This is for two reasons: - // 1. colorSurfaceVariant is used with the assumption that the view that is using it - // is not elevated and is therefore not colored. This view is elevated. - // 2. The way a solid color plays along with a ripple just doesnt look that good. + // we use colorSecondary instead of colorSurfaceVariant. This is because + // colorSurfaceVariant is used with the assumption that the view that is using it is + // not elevated and is therefore not colored. This view is elevated. binding.playbackProgressBar.trackColor = MaterialColors.compositeARGBWithAlpha( R.attr.colorSecondary.resolveAttr(context), (255 * 0.2).toInt() ) } override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets { - updatePadding(bottom = insets.systemBarsCompat.bottom) + // Since we swipe up this view, we need to make sure it does not collide with + // any gesture events. So, apply the system gesture insets if present and then + // only default to the system bar insets when there are no other options. + val gesturePadding = when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> { + insets.getInsets(WindowInsets.Type.systemGestures()).bottom + } + + Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> { + @Suppress("DEPRECATION") + insets.systemGestureInsets.bottom + } + + else -> 0 + } + + updatePadding( + bottom = + if (gesturePadding != 0) + gesturePadding + else + insets.systemBarInsetsCompat.bottom + ) + return insets } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt index ca8d0f7b6..03b2b9663 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt @@ -34,7 +34,7 @@ import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.playback.state.LoopMode import org.oxycblt.auxio.ui.memberBinding import org.oxycblt.auxio.util.logD -import org.oxycblt.auxio.util.systemBarsCompat +import org.oxycblt.auxio.util.systemBarInsetsCompat /** * A [Fragment] that displays more information about the song, along with more media controls. @@ -62,7 +62,7 @@ class PlaybackFragment : Fragment() { binding.detailModel = detailModel binding.root.setOnApplyWindowInsetsListener { _, insets -> - val bars = insets.systemBarsCompat + val bars = insets.systemBarInsetsCompat binding.root.updatePadding( top = bars.top, diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackLayout.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackLayout.kt index 0c5c668e9..afa67d5e9 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackLayout.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackLayout.kt @@ -3,10 +3,8 @@ package org.oxycblt.auxio.playback import android.content.Context import android.content.res.ColorStateList import android.graphics.Canvas -import android.graphics.Insets import android.graphics.Rect import android.graphics.drawable.LayerDrawable -import android.os.Build import android.os.Bundle import android.os.Parcelable import android.util.AttributeSet @@ -26,9 +24,10 @@ import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.R import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.util.replaceInsetsCompat import org.oxycblt.auxio.util.resolveAttr import org.oxycblt.auxio.util.resolveDrawable -import org.oxycblt.auxio.util.systemBarsCompat +import org.oxycblt.auxio.util.systemBarInsetsCompat import kotlin.math.abs import kotlin.math.max import kotlin.math.min @@ -169,7 +168,7 @@ class PlaybackLayout @JvmOverloads constructor( } catch (e: Exception) { // Band-aid to stop the app crashing if we have to swap out the content view // without warning (which we have to do sometimes because android is the worst - // thing ever + // thing ever) } } } @@ -379,29 +378,11 @@ class PlaybackLayout @JvmOverloads constructor( // We kind to do a reverse-measure to figure out how we should inset this view. // Find how much space is lost by the panel and then combine that with the // bottom inset to find how much space we should apply. - val bars = insets.systemBarsCompat + val bars = insets.systemBarInsetsCompat val consumedByPanel = computePanelTopPosition(panelOffset) - measuredHeight val adjustedBottomInset = (consumedByPanel + bars.bottom).coerceAtLeast(0) - return when { - Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> { - WindowInsets.Builder(insets) - .setInsets( - WindowInsets.Type.systemBars(), - Insets.of(bars.left, bars.top, bars.right, adjustedBottomInset) - ) - .build() - } - - Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 -> { - @Suppress("DEPRECATION") - insets.replaceSystemWindowInsets( - bars.left, bars.top, bars.right, adjustedBottomInset - ) - } - - else -> insets - } + return insets.replaceInsetsCompat(bars.left, bars.top, bars.right, adjustedBottomInset) } override fun onSaveInstanceState(): Parcelable = Bundle().apply { @@ -536,8 +517,7 @@ class PlaybackLayout @JvmOverloads constructor( /** * Do the nice view animations that occur whenever we slide up the playback panel. * The way I transition is largely inspired by Android 12's notification panel, with the - * compact view fading out completely before the panel view fades in. We don't fade out the - * content though so we have cohesion between the other sliding transitions. + * compact view fading out completely before the panel view fades in. */ private fun updatePanelTransition() { val ratio = max(panelOffset, 0f) @@ -546,7 +526,6 @@ class PlaybackLayout @JvmOverloads constructor( val halfOutRatio = min(ratio / 0.5f, 1f) val halfInRatio = max(ratio - 0.5f, 0f) / 0.5f - // Optimize out drawing for this view completely contentView.apply { alpha = outRatio isInvisible = alpha == 0f @@ -569,7 +548,7 @@ class PlaybackLayout @JvmOverloads constructor( // [reminder that this view also applies the bottom window inset] and we can't // apply padding to the whole container layout since that would adjust the size // of the playback view. This seems to be the least obtrusive way to do this. - lastInsets?.systemBarsCompat?.let { bars -> + lastInsets?.systemBarInsetsCompat?.let { bars -> val params = layoutParams as FrameLayout.LayoutParams val oldTopMargin = params.topMargin diff --git a/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt index c0dab74a1..64cb1bf26 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt @@ -38,7 +38,7 @@ import org.oxycblt.auxio.databinding.FragmentAboutBinding import org.oxycblt.auxio.home.HomeViewModel import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.showToast -import org.oxycblt.auxio.util.systemBarsCompat +import org.oxycblt.auxio.util.systemBarInsetsCompat /** * A [BottomSheetDialogFragment] that shows Auxio's about screen. @@ -55,7 +55,7 @@ class AboutFragment : Fragment() { val binding = FragmentAboutBinding.inflate(layoutInflater) binding.aboutContents.setOnApplyWindowInsetsListener { _, insets -> - binding.aboutContents.updatePadding(bottom = insets.systemBarsCompat.bottom) + binding.aboutContents.updatePadding(bottom = insets.systemBarInsetsCompat.bottom) insets } diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt index 1a95d5bf1..57eeae1b9 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt @@ -40,7 +40,7 @@ import org.oxycblt.auxio.settings.pref.IntListPreference import org.oxycblt.auxio.util.isNight import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.showToast -import org.oxycblt.auxio.util.systemBarsCompat +import org.oxycblt.auxio.util.systemBarInsetsCompat /** * The actual fragment containing the settings menu. Inherits [PreferenceFragmentCompat]. @@ -64,7 +64,7 @@ class SettingsListFragment : PreferenceFragmentCompat() { clipToPadding = false setOnApplyWindowInsetsListener { _, insets -> - updatePadding(bottom = insets.systemBarsCompat.bottom) + updatePadding(bottom = insets.systemBarInsetsCompat.bottom) insets } diff --git a/app/src/main/java/org/oxycblt/auxio/ui/EdgeAppBarLayout.kt b/app/src/main/java/org/oxycblt/auxio/ui/EdgeAppBarLayout.kt index 5dd3b8f8c..60f6ff74c 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/EdgeAppBarLayout.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/EdgeAppBarLayout.kt @@ -30,7 +30,7 @@ import androidx.core.content.res.ResourcesCompat import androidx.core.view.updatePadding import com.google.android.material.appbar.AppBarLayout import org.oxycblt.auxio.util.logE -import org.oxycblt.auxio.util.systemBarsCompat +import org.oxycblt.auxio.util.systemBarInsetsCompat /** * An [AppBarLayout] that fixes a bug with the default implementation where the lifted state @@ -67,7 +67,7 @@ open class EdgeAppBarLayout @JvmOverloads constructor( override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets { super.onApplyWindowInsets(insets) - updatePadding(top = insets.systemBarsCompat.top) + updatePadding(top = insets.systemBarInsetsCompat.top) return insets } diff --git a/app/src/main/java/org/oxycblt/auxio/ui/EdgeRecyclerView.kt b/app/src/main/java/org/oxycblt/auxio/ui/EdgeRecyclerView.kt index 93d2f9184..8f8fc4b1d 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/EdgeRecyclerView.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/EdgeRecyclerView.kt @@ -23,7 +23,7 @@ import android.util.AttributeSet import android.view.WindowInsets import androidx.core.view.updatePadding import androidx.recyclerview.widget.RecyclerView -import org.oxycblt.auxio.util.systemBarsCompat +import org.oxycblt.auxio.util.systemBarInsetsCompat /** * A [RecyclerView] that automatically applies insets to itself. @@ -34,7 +34,7 @@ class EdgeRecyclerView @JvmOverloads constructor( defStyleAttr: Int = -1 ) : RecyclerView(context, attrs, defStyleAttr) { override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets { - updatePadding(bottom = insets.systemBarsCompat.bottom) + updatePadding(bottom = insets.systemBarInsetsCompat.bottom) return insets } } diff --git a/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt b/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt index 967fcea9c..4641ee208 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt @@ -122,7 +122,7 @@ fun @receiver:AttrRes Int.resolveAttr(context: Context): Int { * Resolve window insets in a version-aware manner. This can be used to apply padding to * a view that properly follows all the frustrating changes that were made between 8-11. */ -val WindowInsets.systemBarsCompat: Rect get() { +val WindowInsets.systemBarInsetsCompat: Rect get() { return when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> { getInsets(WindowInsets.Type.systemBars()).run {