From 1244db73634f3971c16e59921bc81d93f189fedb Mon Sep 17 00:00:00 2001 From: Alex Vanyo Date: Mon, 18 Jul 2022 17:11:11 -0700 Subject: [PATCH] Add support for systemBarsBehavior --- .../SystemBarsVisibilitySample.kt | 65 ++++++++++++++++- systemuicontroller/api/current.api | 3 + .../systemuicontroller/SystemUiController.kt | 16 +++++ .../ActivityRememberSystemUiControllerTest.kt | 55 +++++++++++++++ .../ActivitySystemUiControllerTest.kt | 47 +++++++++++++ .../DialogRememberSystemUiControllerTest.kt | 70 +++++++++++++++++++ .../DialogSystemUiControllerTest.kt | 49 +++++++++++++ 7 files changed, 302 insertions(+), 3 deletions(-) diff --git a/sample/src/main/java/com/google/accompanist/sample/systemuicontroller/SystemBarsVisibilitySample.kt b/sample/src/main/java/com/google/accompanist/sample/systemuicontroller/SystemBarsVisibilitySample.kt index 95643a63d..fc50083ed 100644 --- a/sample/src/main/java/com/google/accompanist/sample/systemuicontroller/SystemBarsVisibilitySample.kt +++ b/sample/src/main/java/com/google/accompanist/sample/systemuicontroller/SystemBarsVisibilitySample.kt @@ -20,22 +20,31 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material.Button +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.material.TopAppBar import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import com.google.accompanist.pager.ExperimentalPagerApi +import androidx.core.view.WindowInsetsControllerCompat import com.google.accompanist.sample.AccompanistSampleTheme import com.google.accompanist.sample.R import com.google.accompanist.systemuicontroller.rememberSystemUiController @@ -54,7 +63,6 @@ class SystemBarsVisibilitySample : ComponentActivity() { } } -@OptIn(ExperimentalPagerApi::class) @Composable private fun Sample() { // Get the current SystemUiController @@ -69,10 +77,61 @@ private fun Sample() { modifier = Modifier.fillMaxSize() ) { padding -> Column( - modifier = Modifier.fillMaxSize().padding(padding), + modifier = Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(padding), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { + Box { + var isShowingDropdownMenu by remember { mutableStateOf(false) } + + Button( + onClick = { + isShowingDropdownMenu = true + }, + modifier = Modifier + .fillMaxWidth(0.7f) + .padding(vertical = 8.dp) + ) { + Text(text = "Change System Bars Behavior") + } + + DropdownMenu( + expanded = isShowingDropdownMenu, + onDismissRequest = { isShowingDropdownMenu = false } + ) { + DropdownMenuItem( + onClick = { + systemUiController.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH + isShowingDropdownMenu = false + } + ) { + Text("BEHAVIOR_SHOW_BARS_BY_TOUCH") + } + DropdownMenuItem( + onClick = { + systemUiController.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE + isShowingDropdownMenu = false + } + ) { + Text("BEHAVIOR_SHOW_BARS_BY_SWIPE") + } + DropdownMenuItem( + onClick = { + systemUiController.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + isShowingDropdownMenu = false + } + ) { + Text("BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE") + } + } + } + /** Status bar */ Button( diff --git a/systemuicontroller/api/current.api b/systemuicontroller/api/current.api index f8f13af24..0c1425005 100644 --- a/systemuicontroller/api/current.api +++ b/systemuicontroller/api/current.api @@ -4,6 +4,7 @@ package com.google.accompanist.systemuicontroller { @androidx.compose.runtime.Stable public interface SystemUiController { method public boolean getNavigationBarDarkContentEnabled(); method public boolean getStatusBarDarkContentEnabled(); + method public int getSystemBarsBehavior(); method public default boolean getSystemBarsDarkContentEnabled(); method public boolean isNavigationBarContrastEnforced(); method public boolean isNavigationBarVisible(); @@ -16,6 +17,7 @@ package com.google.accompanist.systemuicontroller { method public void setStatusBarColor(long color, optional boolean darkIcons, optional kotlin.jvm.functions.Function1 transformColorForLightContent); method public void setStatusBarDarkContentEnabled(boolean statusBarDarkContentEnabled); method public void setStatusBarVisible(boolean isStatusBarVisible); + method public void setSystemBarsBehavior(int systemBarsBehavior); method public default void setSystemBarsColor(long color, optional boolean darkIcons, optional boolean isNavigationBarContrastEnforced, optional kotlin.jvm.functions.Function1 transformColorForLightContent); method public default void setSystemBarsDarkContentEnabled(boolean value); method public default void setSystemBarsVisible(boolean value); @@ -25,6 +27,7 @@ package com.google.accompanist.systemuicontroller { property public default boolean isSystemBarsVisible; property public abstract boolean navigationBarDarkContentEnabled; property public abstract boolean statusBarDarkContentEnabled; + property public abstract int systemBarsBehavior; property public default boolean systemBarsDarkContentEnabled; } diff --git a/systemuicontroller/src/main/java/com/google/accompanist/systemuicontroller/SystemUiController.kt b/systemuicontroller/src/main/java/com/google/accompanist/systemuicontroller/SystemUiController.kt index 44196e991..61307834d 100644 --- a/systemuicontroller/src/main/java/com/google/accompanist/systemuicontroller/SystemUiController.kt +++ b/systemuicontroller/src/main/java/com/google/accompanist/systemuicontroller/SystemUiController.kt @@ -34,6 +34,7 @@ import androidx.compose.ui.window.DialogWindowProvider import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat /** * A class which provides easy-to-use utilities for updating the System UI bar @@ -44,6 +45,15 @@ import androidx.core.view.WindowInsetsCompat @Stable interface SystemUiController { + /** + * Control for the behavior of the system bars. This value should be one of the + * [WindowInsetsControllerCompat] behavior constants: + * [WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH], + * [WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE] and + * [WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE]. + */ + var systemBarsBehavior: Int + /** * Property which holds the status bar visibility. If set to true, show the status bar, * otherwise hide the status bar. @@ -242,6 +252,12 @@ internal class AndroidSystemUiController( }.toArgb() } + override var systemBarsBehavior: Int + get() = windowInsetsController?.systemBarsBehavior ?: 0 + set(value) { + windowInsetsController?.systemBarsBehavior = value + } + override var isStatusBarVisible: Boolean get() { return ViewCompat.getRootWindowInsets(view) diff --git a/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/ActivityRememberSystemUiControllerTest.kt b/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/ActivityRememberSystemUiControllerTest.kt index 0c8396ef1..a25465c40 100644 --- a/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/ActivityRememberSystemUiControllerTest.kt +++ b/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/ActivityRememberSystemUiControllerTest.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.FlakyTest import androidx.test.filters.SdkSuppress @@ -245,6 +246,60 @@ class ActivityRememberSystemUiControllerTest { } } + @Test + @SdkSuppress(minSdkVersion = 30) // TODO: https://issuetracker.google.com/issues/189366125 + fun systemBarsBehavior_showBarsByTouch() { + lateinit var systemUiController: SystemUiController + + rule.setContent { + systemUiController = rememberSystemUiController() + } + + rule.activityRule.scenario.onActivity { + systemUiController.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH + } + + assertThat(WindowCompat.getInsetsController(window, contentView).systemBarsBehavior) + .isEqualTo(WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH) + } + + @Test + @SdkSuppress(minSdkVersion = 30) // TODO: https://issuetracker.google.com/issues/189366125 + fun systemBarsBehavior_showBarsBySwipe() { + lateinit var systemUiController: SystemUiController + + rule.setContent { + systemUiController = rememberSystemUiController() + } + + rule.activityRule.scenario.onActivity { + systemUiController.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE + } + + assertThat(WindowCompat.getInsetsController(window, contentView).systemBarsBehavior) + .isEqualTo(WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE) + } + + @Test + @SdkSuppress(minSdkVersion = 30) // TODO: https://issuetracker.google.com/issues/189366125 + fun systemBarsBehavior_showTransientBarsBySwipe() { + lateinit var systemUiController: SystemUiController + + rule.setContent { + systemUiController = rememberSystemUiController() + } + + rule.activityRule.scenario.onActivity { + systemUiController.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + } + + assertThat(WindowCompat.getInsetsController(window, contentView).systemBarsBehavior) + .isEqualTo(WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE) + } + @Test @FlakyTest(detail = "https://github.com/google/accompanist/issues/491") @SdkSuppress(minSdkVersion = 23) // rootWindowInsets which work diff --git a/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/ActivitySystemUiControllerTest.kt b/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/ActivitySystemUiControllerTest.kt index 81fc0f382..ca03015f7 100644 --- a/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/ActivitySystemUiControllerTest.kt +++ b/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/ActivitySystemUiControllerTest.kt @@ -24,6 +24,7 @@ import androidx.compose.ui.graphics.Color import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.FlakyTest @@ -225,6 +226,52 @@ class ActivitySystemUiControllerTest { } } + @Test + @SdkSuppress(minSdkVersion = 30) // TODO: https://issuetracker.google.com/issues/189366125 + fun systemBarsBehavior_showBarsByTouch() { + val controller = rule.scenario.withActivity { + AndroidSystemUiController(contentView, window) + } + + rule.scenario.onActivity { + controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH + } + + assertThat(WindowCompat.getInsetsController(window, contentView).systemBarsBehavior) + .isEqualTo(WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH) + } + + @Test + @SdkSuppress(minSdkVersion = 30) // TODO: https://issuetracker.google.com/issues/189366125 + fun systemBarsBehavior_showBarsBySwipe() { + val controller = rule.scenario.withActivity { + AndroidSystemUiController(contentView, window) + } + + rule.scenario.onActivity { + controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE + } + + assertThat(WindowCompat.getInsetsController(window, contentView).systemBarsBehavior) + .isEqualTo(WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE) + } + + @Test + @SdkSuppress(minSdkVersion = 30) // TODO: https://issuetracker.google.com/issues/189366125 + fun systemBarsBehavior_showTransientBarsBySwipe() { + val controller = rule.scenario.withActivity { + AndroidSystemUiController(contentView, window) + } + + rule.scenario.onActivity { + controller.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + } + + assertThat(WindowCompat.getInsetsController(window, contentView).systemBarsBehavior) + .isEqualTo(WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE) + } + @Test @FlakyTest(detail = "https://github.com/google/accompanist/issues/491") @SdkSuppress(minSdkVersion = 23) // rootWindowInsets which work diff --git a/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/DialogRememberSystemUiControllerTest.kt b/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/DialogRememberSystemUiControllerTest.kt index 424409f67..e3e8c30b7 100644 --- a/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/DialogRememberSystemUiControllerTest.kt +++ b/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/DialogRememberSystemUiControllerTest.kt @@ -29,6 +29,7 @@ import androidx.compose.ui.window.DialogWindowProvider import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.FlakyTest import androidx.test.filters.SdkSuppress @@ -286,6 +287,75 @@ class DialogRememberSystemUiControllerTest { } } + @Test + @SdkSuppress(minSdkVersion = 30) // TODO: https://issuetracker.google.com/issues/189366125 + fun systemBarsBehavior_showBarsByTouch() { + lateinit var systemUiController: SystemUiController + + rule.setContent { + Dialog(onDismissRequest = {}) { + window = (LocalView.current.parent as DialogWindowProvider).window + contentView = LocalView.current + + systemUiController = rememberSystemUiController() + } + } + + rule.activityRule.scenario.onActivity { + systemUiController.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH + } + + assertThat(WindowCompat.getInsetsController(window, contentView).systemBarsBehavior) + .isEqualTo(WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH) + } + + @Test + @SdkSuppress(minSdkVersion = 30) // TODO: https://issuetracker.google.com/issues/189366125 + fun systemBarsBehavior_showBarsBySwipe() { + lateinit var systemUiController: SystemUiController + + rule.setContent { + Dialog(onDismissRequest = {}) { + window = (LocalView.current.parent as DialogWindowProvider).window + contentView = LocalView.current + + systemUiController = rememberSystemUiController() + } + } + + rule.activityRule.scenario.onActivity { + systemUiController.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE + } + + assertThat(WindowCompat.getInsetsController(window, contentView).systemBarsBehavior) + .isEqualTo(WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE) + } + + @Test + @SdkSuppress(minSdkVersion = 30) // TODO: https://issuetracker.google.com/issues/189366125 + fun systemBarsBehavior_showTransientBarsBySwipe() { + lateinit var systemUiController: SystemUiController + + rule.setContent { + Dialog(onDismissRequest = {}) { + window = (LocalView.current.parent as DialogWindowProvider).window + contentView = LocalView.current + + systemUiController = rememberSystemUiController() + } + } + + rule.activityRule.scenario.onActivity { + systemUiController.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + } + + assertThat(WindowCompat.getInsetsController(window, contentView).systemBarsBehavior) + .isEqualTo(WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE) + } + @Test @FlakyTest(detail = "https://github.com/google/accompanist/issues/491") @SdkSuppress(minSdkVersion = 23) // rootWindowInsets which work diff --git a/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/DialogSystemUiControllerTest.kt b/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/DialogSystemUiControllerTest.kt index 1838c0949..8678f9c22 100644 --- a/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/DialogSystemUiControllerTest.kt +++ b/systemuicontroller/src/sharedTest/kotlin/com/google/accompanist/systemuicontroller/DialogSystemUiControllerTest.kt @@ -27,6 +27,7 @@ import androidx.compose.ui.graphics.Color import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.FlakyTest @@ -244,6 +245,54 @@ class DialogSystemUiControllerTest { } } + @Test + @SdkSuppress(minSdkVersion = 30) // TODO: https://issuetracker.google.com/issues/189366125 + fun systemBarsBehavior_showBarsByTouch() { + val controller = rule.scenario.withActivity { + AndroidSystemUiController(contentView, window) + } + + rule.scenario.onActivity { + controller.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH + } + + assertThat(WindowCompat.getInsetsController(window, contentView).systemBarsBehavior) + .isEqualTo(WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH) + } + + @Test + @SdkSuppress(minSdkVersion = 30) // TODO: https://issuetracker.google.com/issues/189366125 + fun systemBarsBehavior_showBarsBySwipe() { + val controller = rule.scenario.withActivity { + AndroidSystemUiController(contentView, window) + } + + rule.scenario.onActivity { + controller.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE + } + + assertThat(WindowCompat.getInsetsController(window, contentView).systemBarsBehavior) + .isEqualTo(WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE) + } + + @Test + @SdkSuppress(minSdkVersion = 30) // TODO: https://issuetracker.google.com/issues/189366125 + fun systemBarsBehavior_showTransientBarsBySwipe() { + val controller = rule.scenario.withActivity { + AndroidSystemUiController(contentView, window) + } + + rule.scenario.onActivity { + controller.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + } + + assertThat(WindowCompat.getInsetsController(window, contentView).systemBarsBehavior) + .isEqualTo(WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE) + } + @Test @FlakyTest(detail = "https://github.com/google/accompanist/issues/491") @SdkSuppress(minSdkVersion = 23) // rootWindowInsets which work