Force the app dark/light theme in the Gallery app (1/2)

Before this CL, the Gallery app would use a boolean isDarkTheme that
would be toggled and passed to the SystemUITheme to force set the
dark/light theme of the app. However, this does not work for Views and
the AndroidColors, for which we need to set the app dark/light theme
using UiModeManager.

Bug: 238993727
Test: Builds
Change-Id: Ic3efb42d371c6aac8c2a6297a0cb192a780903cd
This commit is contained in:
Jordan Demeulenaere
2022-07-25 17:45:38 +02:00
parent f9e90fd2ab
commit 33470b902e
9 changed files with 98 additions and 49 deletions

View File

@@ -37,7 +37,7 @@ val LocalAndroidColorScheme =
* Important: Use M3 colors from MaterialTheme.colorScheme whenever possible instead. In the future, * Important: Use M3 colors from MaterialTheme.colorScheme whenever possible instead. In the future,
* most of the colors in this class will be removed in favor of their M3 counterpart. * most of the colors in this class will be removed in favor of their M3 counterpart.
*/ */
class AndroidColorScheme internal constructor(private val context: Context) { class AndroidColorScheme internal constructor(context: Context) {
val colorPrimary = getColor(context, R.attr.colorPrimary) val colorPrimary = getColor(context, R.attr.colorPrimary)
val colorPrimaryDark = getColor(context, R.attr.colorPrimaryDark) val colorPrimaryDark = getColor(context, R.attr.colorPrimaryDark)
val colorAccent = getColor(context, R.attr.colorAccent) val colorAccent = getColor(context, R.attr.colorAccent)

View File

@@ -34,6 +34,7 @@ android_library {
], ],
static_libs: [ static_libs: [
"SystemUI-core",
"SystemUIComposeCore", "SystemUIComposeCore",
"SystemUIComposeFeatures", "SystemUIComposeFeatures",

View File

@@ -16,7 +16,40 @@
--> -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.android.systemui.compose.gallery"> package="com.android.systemui.compose.gallery">
<!-- To emulate a display size and density. --> <!-- To emulate a display size and density. -->
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<application
android:name="android.app.Application"
android:appComponentFactory="androidx.core.app.AppComponentFactory"
tools:replace="android:name,android:appComponentFactory">
<!-- Disable providers from SystemUI -->
<provider android:name="com.android.systemui.keyguard.KeyguardSliceProvider"
android:authorities="com.android.systemui.test.keyguard.disabled"
android:enabled="false"
tools:replace="android:authorities"
tools:node="remove" />
<provider android:name="com.google.android.systemui.keyguard.KeyguardSliceProviderGoogle"
android:authorities="com.android.systemui.test.keyguard.disabled"
android:enabled="false"
tools:replace="android:authorities"
tools:node="remove" />
<provider android:name="com.android.keyguard.clock.ClockOptionsProvider"
android:authorities="com.android.systemui.test.keyguard.clock.disabled"
android:enabled="false"
tools:replace="android:authorities"
tools:node="remove" />
<provider android:name="com.android.systemui.people.PeopleProvider"
android:authorities="com.android.systemui.test.people.disabled"
android:enabled="false"
tools:replace="android:authorities"
tools:node="remove" />
<provider android:name="androidx.core.content.FileProvider"
android:authorities="com.android.systemui.test.fileprovider.disabled"
android:enabled="false"
tools:replace="android:authorities"
tools:node="remove"/>
</application>
</manifest> </manifest>

View File

@@ -16,6 +16,7 @@
--> -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.android.systemui.compose.gallery.app"> package="com.android.systemui.compose.gallery.app">
<application <application
android:allowBackup="true" android:allowBackup="true"
@@ -23,7 +24,8 @@
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.SystemUIGallery"> android:theme="@style/Theme.SystemUI.Gallery"
tools:replace="android:icon,android:theme,android:label">
<activity <activity
android:name="com.android.systemui.compose.gallery.GalleryActivity" android:name="com.android.systemui.compose.gallery.GalleryActivity"
android:exported="true" android:exported="true"

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="Theme.SystemUIGallery" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="android:statusBarColor" tools:targetApi="l">
@android:color/transparent
</item>
<item name="android:navigationBarColor" tools:targetApi="l">
@android:color/transparent
</item>
</style>
</resources>

View File

@@ -15,7 +15,10 @@
limitations under the License. limitations under the License.
--> -->
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<style name="Theme.SystemUIGallery" parent="Theme.AppCompat.DayNight.NoActionBar"> <style name="Theme.SystemUI.Gallery">
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:statusBarColor" tools:targetApi="l"> <item name="android:statusBarColor" tools:targetApi="l">
@android:color/transparent @android:color/transparent
</item> </item>

View File

@@ -9,11 +9,12 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.BrightnessHigh import androidx.compose.material.icons.filled.DarkMode
import androidx.compose.material.icons.filled.BrightnessLow
import androidx.compose.material.icons.filled.FormatSize import androidx.compose.material.icons.filled.FormatSize
import androidx.compose.material.icons.filled.FormatTextdirectionLToR import androidx.compose.material.icons.filled.FormatTextdirectionLToR
import androidx.compose.material.icons.filled.FormatTextdirectionRToL import androidx.compose.material.icons.filled.FormatTextdirectionRToL
import androidx.compose.material.icons.filled.InvertColors
import androidx.compose.material.icons.filled.LightMode
import androidx.compose.material.icons.filled.Smartphone import androidx.compose.material.icons.filled.Smartphone
import androidx.compose.material.icons.filled.Tablet import androidx.compose.material.icons.filled.Tablet
import androidx.compose.material3.Button import androidx.compose.material3.Button
@@ -44,12 +45,13 @@ enum class FontScale(val scale: Float) {
/** A configuration panel that allows to toggle the theme, font scale and layout direction. */ /** A configuration panel that allows to toggle the theme, font scale and layout direction. */
@Composable @Composable
fun ConfigurationControls( fun ConfigurationControls(
isDarkTheme: Boolean, theme: Theme,
fontScale: FontScale, fontScale: FontScale,
layoutDirection: LayoutDirection, layoutDirection: LayoutDirection,
onChangeTheme: () -> Unit, onChangeTheme: () -> Unit,
onChangeLayoutDirection: () -> Unit, onChangeLayoutDirection: () -> Unit,
onChangeFontScale: () -> Unit, onChangeFontScale: () -> Unit,
modifier: Modifier = Modifier,
) { ) {
// The display we are emulating, if any. // The display we are emulating, if any.
var emulatedDisplayName by rememberSaveable { mutableStateOf<String?>(null) } var emulatedDisplayName by rememberSaveable { mutableStateOf<String?>(null) }
@@ -84,18 +86,26 @@ fun ConfigurationControls(
// TODO(b/231131244): Fork FlowRow from Accompanist and use that instead to make sure that users // TODO(b/231131244): Fork FlowRow from Accompanist and use that instead to make sure that users
// don't miss any available configuration. // don't miss any available configuration.
LazyRow { LazyRow(modifier) {
// Dark/light theme. // Dark/light theme.
item { item {
TextButton(onChangeTheme) { TextButton(onChangeTheme) {
val text: String val text: String
val icon: ImageVector val icon: ImageVector
if (isDarkTheme) {
icon = Icons.Default.BrightnessHigh when (theme) {
text = "Dark" Theme.System -> {
} else { icon = Icons.Default.InvertColors
icon = Icons.Default.BrightnessLow text = "System"
text = "Light" }
Theme.Dark -> {
icon = Icons.Default.DarkMode
text = "Dark"
}
Theme.Light -> {
icon = Icons.Default.LightMode
text = "Light"
}
} }
Icon(icon, null) Icon(icon, null)

View File

@@ -16,6 +16,8 @@
package com.android.systemui.compose.gallery package com.android.systemui.compose.gallery
import android.app.UiModeManager
import android.content.Context
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
@@ -23,7 +25,7 @@ import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.SideEffect import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
@@ -33,22 +35,46 @@ class GalleryActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
val uiModeManager = getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
setContent { setContent {
val isSystemInDarkTheme = isSystemInDarkTheme() var theme by rememberSaveable { mutableStateOf(Theme.System) }
var isDarkTheme by remember { mutableStateOf(isSystemInDarkTheme) } val onChangeTheme = {
val onChangeTheme = { isDarkTheme = !isDarkTheme } // Change to the next theme for a toggle behavior.
theme =
when (theme) {
Theme.System -> Theme.Dark
Theme.Dark -> Theme.Light
Theme.Light -> Theme.System
}
}
val isSystemInDarkTheme = isSystemInDarkTheme()
val isDark = theme == Theme.Dark || (theme == Theme.System && isSystemInDarkTheme)
val useDarkIcons = !isDark
val systemUiController = rememberSystemUiController() val systemUiController = rememberSystemUiController()
val useDarkIcons = !isDarkTheme
SideEffect { SideEffect {
systemUiController.setSystemBarsColor( systemUiController.setSystemBarsColor(
color = Color.Transparent, color = Color.Transparent,
darkIcons = useDarkIcons, darkIcons = useDarkIcons,
) )
uiModeManager.setApplicationNightMode(
when (theme) {
Theme.System -> UiModeManager.MODE_NIGHT_AUTO
Theme.Dark -> UiModeManager.MODE_NIGHT_YES
Theme.Light -> UiModeManager.MODE_NIGHT_NO
}
)
} }
GalleryApp(isDarkTheme, onChangeTheme) GalleryApp(theme, onChangeTheme)
} }
} }
} }
enum class Theme {
System,
Dark,
Light,
}

View File

@@ -65,7 +65,7 @@ private fun MainContent() {
*/ */
@Composable @Composable
fun GalleryApp( fun GalleryApp(
isDarkTheme: Boolean, theme: Theme,
onChangeTheme: () -> Unit, onChangeTheme: () -> Unit,
) { ) {
val systemFontScale = LocalDensity.current.fontScale val systemFontScale = LocalDensity.current.fontScale
@@ -100,14 +100,14 @@ fun GalleryApp(
LocalDensity provides density, LocalDensity provides density,
LocalLayoutDirection provides layoutDirection, LocalLayoutDirection provides layoutDirection,
) { ) {
SystemUITheme(isDarkTheme) { SystemUITheme {
Surface( Surface(
Modifier.fillMaxSize(), Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background, color = MaterialTheme.colorScheme.background,
) { ) {
Column(Modifier.fillMaxSize().systemBarsPadding().padding(16.dp)) { Column(Modifier.fillMaxSize().systemBarsPadding().padding(16.dp)) {
ConfigurationControls( ConfigurationControls(
isDarkTheme, theme,
fontScale, fontScale,
layoutDirection, layoutDirection,
onChangeTheme, onChangeTheme,