xref: /aosp_15_r20/developers/build/prebuilts/gradle/DarkTheme/README.md (revision d353a188ca6ec4b5eba25b5fbd7bcb8ce61322fb)
1*d353a188SXin Li
2*d353a188SXin LiAndroid DarkTheme Sample
3*d353a188SXin Li===================================
4*d353a188SXin Li
5*d353a188SXin LiSample demonstrating the different ways to support Dark Mode on Android.
6*d353a188SXin Li            Uses the Material Design Components Library.
7*d353a188SXin Li
8*d353a188SXin LiIntroduction
9*d353a188SXin Li------------
10*d353a188SXin Li
11*d353a188SXin LiAndroid Q has explicit user support for Dark Mode, allowing users to choose
12*d353a188SXin Liwhether the device theme is dark or not. There are multiple ways you can allow
13*d353a188SXin LiDark Mode in your app:
14*d353a188SXin Li
15*d353a188SXin LiNight mode in AppCompat and Material Components
16*d353a188SXin Li------------
17*d353a188SXin Li
18*d353a188SXin LiAppCompat has had "night mode" APIs for a number of years now. It allows developers to
19*d353a188SXin Liimplement dark mode in their apps using the -night resource qualifier. The [Material Design
20*d353a188SXin LiComponents library][1] builds upon AppCompat and exposes its own DayNight themes.
21*d353a188SXin Li
22*d353a188SXin LiThe DayNight theme in the AndroidX Material Components library provides Dark Theme backwards
23*d353a188SXin Licompatibility down to API 14. The theme we use in the app (specified in
24*d353a188SXin Li`AndroidManifest.xml#L23`) extends from DayNight (`values/styles.xml#L16`).
25*d353a188SXin Li
26*d353a188SXin LiUse theme-defined colours when defining colours for your drawables. For example, we use
27*d353a188SXin Li`?attr/colorOnBackground` for the generic text color of the app (`values/styles.xml#35`).
28*d353a188SXin Li
29*d353a188SXin LiWhen it's not possible to use theme-defined colours, you can use the -night qualifier to
30*d353a188SXin Liextract hard-coded values and switch them out when the configuration changes to night mode.
31*d353a188SXin LiFor example, we use a different primary colour in dark mode. Check `values-night/colors.xml`
32*d353a188SXin Lifor more details. You can also specify custom drawables creating a drawable-night folder.
33*d353a188SXin Li
34*d353a188SXin LiTell AppCompat what mode to use by calling [`AppCompatDelegate.setDefaultNightMode()`][2] or
35*d353a188SXin Li`getDelegate().setLocalNightMode()`. It can take different values:
36*d353a188SXin Li- MODE_NIGHT_YES. Always use the dark theme.
37*d353a188SXin Li- MODE_NIGHT_NO. Always use the light theme (Smart Dark can override it).
38*d353a188SXin Li- MODE_NIGHT_FOLLOW_SYSTEM. Follows the current system setting
39*d353a188SXin Li- MODE_NIGHT_AUTO_BATTERY. Dark when battery saver is enabled, light otherwise.
40*d353a188SXin Li
41*d353a188SXin LiIn the code sample, you can find the code related to this in the `ThemeHelper` class.
42*d353a188SXin Li
43*d353a188SXin LiSmart Dark
44*d353a188SXin Li------------
45*d353a188SXin Li
46*d353a188SXin LiSmart Dark is a new feature in Android Q which can automatically theme a light app to
47*d353a188SXin Lidark by dynamically re-coloring the app being drawn at runtime. It has no direct developer
48*d353a188SXin LiAPIs. It is made for apps which do not have explicit Dark Theme support yet.
49*d353a188SXin Li
50*d353a188SXin LiSmart Dark applies to any theme whose value of `android:isLightTheme=true`. This is set on
51*d353a188SXin Liall of the `Theme.*.Light.*` variants, including those from AppCompat. You can opt-in and opt-out at
52*d353a188SXin Liboth a theme and view level. Opt-in by setting `android:forceDarkAllowed="true"`
53*d353a188SXin Liin the view or theme. Alternatively, you can enable/disable it in the code by calling
54*d353a188SXin Li`View#setForceDarkAllowed(boolean)`.
55*d353a188SXin Li
56*d353a188SXin LiThis feature is implemented in the `PreferencesFragment`. As you can see in the
57*d353a188SXin Li`layout/fragment_preferences.xml` file, all colours are hard-coded to be light-theme suitable.
58*d353a188SXin LiTo make it use Smart Dark, the parent view sets `android:forceDarkAllowed="true"`
59*d353a188SXin Li(you can see it in `layout/fragment_preferences.xml#L19`). In this case, when Smart Dark is
60*d353a188SXin Liactive, this screen will be automatically themed to be dark-mode friendly. The system will
61*d353a188SXin Lichange most of the colours to make that happen.
62*d353a188SXin Li
63*d353a188SXin LiDark Mode in the code sample
64*d353a188SXin Li------------
65*d353a188SXin Li
66*d353a188SXin LiThe user can decide which theme to use within the app. In the Settings screen, the user
67*d353a188SXin Lican choose the Light theme, Dark theme, or System Default (when the app is running on
68*d353a188SXin LiAndroid Q+) or Set by Battery Saver (when running on Android P or earlier). When using the
69*d353a188SXin LiSystem Default option, the system decides the theme based on the Platform System Settings
70*d353a188SXin Liintroduced in Android Q.
71*d353a188SXin Li
72*d353a188SXin LiThese options, that are also listed above, are the settings that Google recommends.
73*d353a188SXin LiAlso, it recommends that this user choice is stored and applied whenever the user opens
74*d353a188SXin Lithe app again. In the code sample, the user preference is automatically stored in
75*d353a188SXin Li`SharedPreferences` because we use the androidX preference library. Check `SettingsFragment`
76*d353a188SXin Liand `preferences.xml` for more information about it. In the `DarkThemeApplication` class,
77*d353a188SXin Liwe retrieve and apply the user theme preference when the user opens the app.
78*d353a188SXin Li
79*d353a188SXin LiNotice that the PreferencesFragment will be only in Dark Mode when the Smart Dark is active.
80*d353a188SXin LiYou can force it by running `adb shell setprop debug.hwui.force_dark true` on your terminal console.
81*d353a188SXin Li
82*d353a188SXin LiHands on
83*d353a188SXin Li------------
84*d353a188SXin Li
85*d353a188SXin LiIn the sample, we make views Dark-Mode friendly in different ways:
86*d353a188SXin Li
87*d353a188SXin Li- *Vectors using tints*. `drawable/ic_brightness_2.xml` is Dark-Mode friendly by
88*d353a188SXin Liusing the `android:tint` attribute.
89*d353a188SXin Li
90*d353a188SXin Li- *Vectors using hard-coded colours*. `drawable/ic_brightness.xml` is Dark-Mode friendly by
91*d353a188SXin Lisetting its View tint in `fragment_welcome.xml#L38`. Also, you can set it programmatically
92*d353a188SXin Lias we do with the tinted menu icon `R.id.action_more`.
93*d353a188SXin Li
94*d353a188SXin Li- *Tinted menu icons*. `R.id.action_more` is tinted programmatically in `MainActivity.java#L85`.
95*d353a188SXin Li
96*d353a188SXin Li- *Different colorPrimary/colorsecondary for light/dark mode*. We define the primary color
97*d353a188SXin Liin `values/styles.xml#L21` where we set "colorPrimary" to `@color/primary`.
98*d353a188SXin Li`@color/primary` is defined in both `values/colors.xml` and `values-night/colors.xml`.
99*d353a188SXin Li
100*d353a188SXin Li- *Text color*. Same way as we did before, the text color is defined in `values/styles.xml`
101*d353a188SXin Liwith the `"android:textColorPrimary"` attribute.
102*d353a188SXin Li
103*d353a188SXin Li- *Window background*. The window background is set in `values/styles.xml` with the
104*d353a188SXin Li`"android:windowBackground"` attribute. The value is set to `@color/background` so if
105*d353a188SXin LiDark Mode is enabled the splash screen is black instead of white.
106*d353a188SXin Li
107*d353a188SXin Li- *Apply variations to a color using ColorStateList*. Check out `color/color_on_primary_mask.xml`.
108*d353a188SXin LiInstead of creating a new color with an alpha in hexadecimal values, we reuse the color and specify
109*d353a188SXin Lithe alpha with a percentage number.
110*d353a188SXin Li
111*d353a188SXin Li- *Enable Smart Dark*. The `PreferenceFragment` is not Dark-Mode friendly. It has all colours
112*d353a188SXin Lihard-coded to be suitable for light mode. To opt the Fragment in for Smart Dark, we set
113*d353a188SXin Li`android:forceDarkAllowed="true"` in the root View of the Fragment. You can find the code
114*d353a188SXin Liin `layout/fragment_preferences.xml#19`.
115*d353a188SXin Li
116*d353a188SXin Li[1]: https://material.io/develop/android/docs/getting-started/
117*d353a188SXin Li[2]: https://developer.android.com/reference/android/support/v7/app/AppCompatDelegate#setdefaultnightmode
118*d353a188SXin Li
119*d353a188SXin LiPre-requisites
120*d353a188SXin Li--------------
121*d353a188SXin Li
122*d353a188SXin Li- Android SDK 29
123*d353a188SXin Li- Android Support Repository
124*d353a188SXin Li
125*d353a188SXin LiScreenshots
126*d353a188SXin Li-------------
127*d353a188SXin Li
128*d353a188SXin Li<img src="screenshots/light_1_welcome.png" height="400" alt="Screenshot"/> <img src="screenshots/light_2_preferences.png" height="400" alt="Screenshot"/> <img src="screenshots/light_3_settings.png" height="400" alt="Screenshot"/> <img src="screenshots/light_4_theme_options.png" height="400" alt="Screenshot"/> <img src="screenshots/dark_1_welcome.png" height="400" alt="Screenshot"/> <img src="screenshots/smart_dark_2_preferences.png" height="400" alt="Screenshot"/> <img src="screenshots/dark_3_settings.png" height="400" alt="Screenshot"/> <img src="screenshots/dark_4_theme_options.png" height="400" alt="Screenshot"/>
129*d353a188SXin Li
130*d353a188SXin LiGetting Started
131*d353a188SXin Li---------------
132*d353a188SXin Li
133*d353a188SXin LiThis sample uses the Gradle build system. To build this project, use the
134*d353a188SXin Li"gradlew build" command or use "Import Project" in Android Studio.
135*d353a188SXin Li
136*d353a188SXin LiSupport
137*d353a188SXin Li-------
138*d353a188SXin Li
139*d353a188SXin Li- Stack Overflow: http://stackoverflow.com/questions/tagged/android
140*d353a188SXin Li
141*d353a188SXin LiIf you've found an error in this sample, please file an issue:
142*d353a188SXin Lihttps://github.com/googlesamples/android-DarkTheme
143*d353a188SXin Li
144*d353a188SXin LiPatches are encouraged, and may be submitted by forking this project and
145*d353a188SXin Lisubmitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
146*d353a188SXin Li
147*d353a188SXin LiLicense
148*d353a188SXin Li-------
149*d353a188SXin Li
150*d353a188SXin LiCopyright 2019 The Android Open Source Project, Inc.
151*d353a188SXin Li
152*d353a188SXin LiLicensed to the Apache Software Foundation (ASF) under one or more contributor
153*d353a188SXin Lilicense agreements.  See the NOTICE file distributed with this work for
154*d353a188SXin Liadditional information regarding copyright ownership.  The ASF licenses this
155*d353a188SXin Lifile to you under the Apache License, Version 2.0 (the "License"); you may not
156*d353a188SXin Liuse this file except in compliance with the License.  You may obtain a copy of
157*d353a188SXin Lithe License at
158*d353a188SXin Li
159*d353a188SXin Lihttps://www.apache.org/licenses/LICENSE-2.0
160*d353a188SXin Li
161*d353a188SXin LiUnless required by applicable law or agreed to in writing, software
162*d353a188SXin Lidistributed under the License is distributed on an "AS IS" BASIS, WITHOUT
163*d353a188SXin LiWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
164*d353a188SXin LiLicense for the specific language governing permissions and limitations under
165*d353a188SXin Lithe License.
166