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,
* 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 colorPrimaryDark = getColor(context, R.attr.colorPrimaryDark)
val colorAccent = getColor(context, R.attr.colorAccent)

View File

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

View File

@@ -16,7 +16,40 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.android.systemui.compose.gallery">
<!-- To emulate a display size and density. -->
<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>

View File

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

View File

@@ -9,11 +9,12 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.BrightnessHigh
import androidx.compose.material.icons.filled.BrightnessLow
import androidx.compose.material.icons.filled.DarkMode
import androidx.compose.material.icons.filled.FormatSize
import androidx.compose.material.icons.filled.FormatTextdirectionLToR
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.Tablet
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. */
@Composable
fun ConfigurationControls(
isDarkTheme: Boolean,
theme: Theme,
fontScale: FontScale,
layoutDirection: LayoutDirection,
onChangeTheme: () -> Unit,
onChangeLayoutDirection: () -> Unit,
onChangeFontScale: () -> Unit,
modifier: Modifier = Modifier,
) {
// The display we are emulating, if any.
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
// don't miss any available configuration.
LazyRow {
LazyRow(modifier) {
// Dark/light theme.
item {
TextButton(onChangeTheme) {
val text: String
val icon: ImageVector
if (isDarkTheme) {
icon = Icons.Default.BrightnessHigh
text = "Dark"
} else {
icon = Icons.Default.BrightnessLow
text = "Light"
when (theme) {
Theme.System -> {
icon = Icons.Default.InvertColors
text = "System"
}
Theme.Dark -> {
icon = Icons.Default.DarkMode
text = "Dark"
}
Theme.Light -> {
icon = Icons.Default.LightMode
text = "Light"
}
}
Icon(icon, null)

View File

@@ -16,6 +16,8 @@
package com.android.systemui.compose.gallery
import android.app.UiModeManager
import android.content.Context
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
@@ -23,7 +25,7 @@ import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
import androidx.core.view.WindowCompat
@@ -33,22 +35,46 @@ class GalleryActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
val uiModeManager = getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
setContent {
val isSystemInDarkTheme = isSystemInDarkTheme()
var isDarkTheme by remember { mutableStateOf(isSystemInDarkTheme) }
val onChangeTheme = { isDarkTheme = !isDarkTheme }
var theme by rememberSaveable { mutableStateOf(Theme.System) }
val onChangeTheme = {
// 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 useDarkIcons = !isDarkTheme
SideEffect {
systemUiController.setSystemBarsColor(
color = Color.Transparent,
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
fun GalleryApp(
isDarkTheme: Boolean,
theme: Theme,
onChangeTheme: () -> Unit,
) {
val systemFontScale = LocalDensity.current.fontScale
@@ -100,14 +100,14 @@ fun GalleryApp(
LocalDensity provides density,
LocalLayoutDirection provides layoutDirection,
) {
SystemUITheme(isDarkTheme) {
SystemUITheme {
Surface(
Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background,
) {
Column(Modifier.fillMaxSize().systemBarsPadding().padding(16.dp)) {
ConfigurationControls(
isDarkTheme,
theme,
fontScale,
layoutDirection,
onChangeTheme,