summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBartlomiej Moskal <bartlomiej.moskal@qt.io>2022-08-02 12:11:56 +0200
committerBartlomiej Moskal <bartlomiej.moskal@qt.io>2022-10-26 17:13:44 +0200
commitb4a9bb1f6a40e6d504c1f48f0d9ea2b70ab1a9f0 (patch)
treee5d14e3250a113836098d8933d4813afce3b976f /src
parentf157e223c21c79ebaf7e5e1a23dbdb3d8da1a59e (diff)
Android: Handle light/dark mode changes
Update Theme's style according to current UiMode. New style.json file for dark mode was added (stored in separate subdirectory 'darkUiMode/'). Theme_DeviceDefault_DayNight[0] is used for extraction for API 29 or higher. Style is updated each time when UiMode is changed. [0]https://developer.android.com/reference/android/R.style#Theme_DeviceDefault_DayNight Task-number: QTBUG-83185 Pick-to: 6.4 6.2 Change-Id: Id26059231f41761d822d494ac6c641bf3cba3322 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java37
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java16
-rw-r--r--src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java10
-rw-r--r--src/android/java/src/org/qtproject/qt/android/bindings/QtLoader.java2
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp5
-rw-r--r--src/plugins/platforms/android/qandroidplatformtheme.cpp81
-rw-r--r--src/plugins/platforms/android/qandroidplatformtheme.h8
7 files changed, 137 insertions, 22 deletions
diff --git a/src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java
index 6792247eeb..672a2e28d3 100644
--- a/src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java
+++ b/src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java
@@ -34,6 +34,7 @@ import android.graphics.drawable.ScaleDrawable;
import android.graphics.drawable.StateListDrawable;
import android.graphics.drawable.VectorDrawable;
import android.os.Build;
+import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
@@ -135,6 +136,42 @@ public class ExtractStyle {
Context m_context;
private final HashMap<String, DrawableCache> m_drawableCache = new HashMap<>();
+ private static final String EXTRACT_STYLE_KEY = "extract.android.style";
+ private static final String EXTRACT_STYLE_MINIMAL_KEY = "extract.android.style.option";
+
+ private static boolean m_missingNormalStyle = false;
+ private static boolean m_missingDarkStyle = false;
+ private static String m_stylePath = null;
+ private static boolean m_extractMinimal = false;
+
+ public static void setup(Bundle loaderParams) {
+ if (loaderParams.containsKey(EXTRACT_STYLE_KEY)) {
+ m_stylePath = loaderParams.getString(EXTRACT_STYLE_KEY);
+
+ boolean darkModeFileMissing = !(new File(m_stylePath + "darkUiMode/style.json").exists());
+ m_missingDarkStyle = Build.VERSION.SDK_INT > 28 && darkModeFileMissing;
+
+ m_missingNormalStyle = !(new File(m_stylePath + "style.json").exists());
+
+ m_extractMinimal = loaderParams.containsKey(EXTRACT_STYLE_MINIMAL_KEY) &&
+ loaderParams.getBoolean(EXTRACT_STYLE_MINIMAL_KEY);
+ }
+ }
+
+ public static void runIfNeeded(Context context, boolean extractDarkMode) {
+ if (m_stylePath == null)
+ return;
+ if (extractDarkMode) {
+ if (m_missingDarkStyle) {
+ new ExtractStyle(context, m_stylePath + "darkUiMode/", m_extractMinimal);
+ m_missingDarkStyle = false;
+ }
+ } else if (m_missingNormalStyle) {
+ new ExtractStyle(context, m_stylePath, m_extractMinimal);
+ m_missingNormalStyle = false;
+ }
+ }
+
public ExtractStyle(Context context, String extractPath, boolean minimal) {
m_minimal = minimal;
m_extractPath = extractPath + "/";
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java
index 63298c0730..ec890d1d61 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java
@@ -84,8 +84,6 @@ public class QtActivityDelegate
private static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables";
private static final String APPLICATION_PARAMETERS_KEY = "application.parameters";
private static final String STATIC_INIT_CLASSES_KEY = "static.init.classes";
- private static final String EXTRACT_STYLE_KEY = "extract.android.style";
- private static final String EXTRACT_STYLE_MINIMAL_KEY = "extract.android.style.option";
public static final int SYSTEM_UI_VISIBILITY_NORMAL = 0;
public static final int SYSTEM_UI_VISIBILITY_FULLSCREEN = 1;
@@ -707,11 +705,8 @@ public class QtActivityDelegate
libraries.remove(libraries.size() - 1);
}
- if (loaderParams.containsKey(EXTRACT_STYLE_KEY)) {
- String path = loaderParams.getString(EXTRACT_STYLE_KEY);
- new ExtractStyle(m_activity, path, loaderParams.containsKey(EXTRACT_STYLE_MINIMAL_KEY) &&
- loaderParams.getBoolean(EXTRACT_STYLE_MINIMAL_KEY));
- }
+ ExtractStyle.setup(loaderParams);
+ ExtractStyle.runIfNeeded(m_activity, isUiModeDark(m_activity.getResources().getConfiguration()));
QtNative.setEnvironmentVariables(loaderParams.getString(ENVIRONMENT_VARIABLES_KEY));
QtNative.setEnvironmentVariable("QT_ANDROID_FONTS_MONOSPACE",
@@ -971,13 +966,20 @@ public class QtActivityDelegate
updateFullScreen();
}
+ boolean isUiModeDark(Configuration config)
+ {
+ return (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
+ }
+
private void handleUiModeChange(int uiMode)
{
switch (uiMode) {
case Configuration.UI_MODE_NIGHT_NO:
+ ExtractStyle.runIfNeeded(m_activity, false);
QtNative.handleUiDarkModeChanged(0);
break;
case Configuration.UI_MODE_NIGHT_YES:
+ ExtractStyle.runIfNeeded(m_activity, true);
QtNative.handleUiDarkModeChanged(1);
break;
}
diff --git a/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java b/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java
index 9cef8146fd..94d3c2dee1 100644
--- a/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java
+++ b/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java
@@ -65,8 +65,14 @@ public class QtActivity extends Activity
public QtActivity()
{
m_loader = new QtActivityLoader(this);
- QT_ANDROID_THEMES = new String[] {"Theme_Holo_Light"};
- QT_ANDROID_DEFAULT_THEME = "Theme_Holo_Light";
+
+ if (Build.VERSION.SDK_INT < 29) {
+ QT_ANDROID_THEMES = new String[] {"Theme_Holo_Light"};
+ QT_ANDROID_DEFAULT_THEME = "Theme_Holo_Light";
+ } else {
+ QT_ANDROID_THEMES = new String[] {"Theme_DeviceDefault_DayNight"};
+ QT_ANDROID_DEFAULT_THEME = "Theme_DeviceDefault_DayNight";
+ }
}
diff --git a/src/android/java/src/org/qtproject/qt/android/bindings/QtLoader.java b/src/android/java/src/org/qtproject/qt/android/bindings/QtLoader.java
index 883c0d6478..fea193a4db 100644
--- a/src/android/java/src/org/qtproject/qt/android/bindings/QtLoader.java
+++ b/src/android/java/src/org/qtproject/qt/android/bindings/QtLoader.java
@@ -331,7 +331,7 @@ public abstract class QtLoader {
}
}
- if (!(new File(stylePath)).exists() && !extractOption.equals("none")) {
+ if (!extractOption.equals("none")) {
loaderParams.putString(EXTRACT_STYLE_KEY, stylePath);
loaderParams.putBoolean(EXTRACT_STYLE_MINIMAL_KEY, extractOption.equals("minimal"));
}
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp
index 57546bdbca..0d5b473477 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -460,7 +460,7 @@ QStringList QAndroidPlatformIntegration::themeNames() const
QPlatformTheme *QAndroidPlatformIntegration::createPlatformTheme(const QString &name) const
{
if (androidThemeName == name)
- return new QAndroidPlatformTheme(m_androidPlatformNativeInterface);
+ return QAndroidPlatformTheme::instance(m_androidPlatformNativeInterface);
return 0;
}
@@ -523,6 +523,9 @@ void QAndroidPlatformIntegration::setAppearance(Qt::Appearance newAppearance)
if (m_appearance == newAppearance)
return;
m_appearance = newAppearance;
+
+ QMetaObject::invokeMethod(qGuiApp,
+ [] () { QAndroidPlatformTheme::instance()->updateAppearance();});
}
void QAndroidPlatformIntegration::setScreenSizeParameters(const QSize &physicalSize,
diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp
index 6f950dc4fb..f11de02d44 100644
--- a/src/plugins/platforms/android/qandroidplatformtheme.cpp
+++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp
@@ -158,6 +158,9 @@ QJsonObject AndroidStyle::loadStyleData()
if (!stylePath.isEmpty() && !stylePath.endsWith(slashChar))
stylePath += slashChar;
+ if (QAndroidPlatformIntegration::appearance() == Qt::Appearance::Dark)
+ stylePath += "darkUiMode/"_L1;
+
Q_ASSERT(!stylePath.isEmpty());
QString androidTheme = QLatin1StringView(qgetenv("QT_ANDROID_THEME"));
@@ -185,13 +188,22 @@ QJsonObject AndroidStyle::loadStyleData()
return document.object();
}
-static std::shared_ptr<AndroidStyle> loadAndroidStyle(QPalette *defaultPalette)
+static void loadAndroidStyle(QPalette *defaultPalette, std::shared_ptr<AndroidStyle> &style)
{
double pixelDensity = QHighDpiScaling::isActive() ? QtAndroid::pixelDensity() : 1.0;
- std::shared_ptr<AndroidStyle> style = std::make_shared<AndroidStyle>();
+ if (style) {
+ style->m_standardPalette = QPalette();
+ style->m_palettes.clear();
+ style->m_fonts.clear();
+ style->m_QWidgetsFonts.clear();
+ } else {
+ style = std::make_shared<AndroidStyle>();
+ }
+
style->m_styleData = AndroidStyle::loadStyleData();
+
if (style->m_styleData.isEmpty())
- return std::shared_ptr<AndroidStyle>();
+ return;
{
QFont font("Droid Sans Mono"_L1, 14.0 * 100 / 72);
@@ -293,11 +305,43 @@ static std::shared_ptr<AndroidStyle> loadAndroidStyle(QPalette *defaultPalette)
// Extract palette information
}
}
- return style;
+}
+
+QAndroidPlatformTheme *QAndroidPlatformTheme::m_instance = nullptr;
+
+QAndroidPlatformTheme *QAndroidPlatformTheme::instance(
+ QAndroidPlatformNativeInterface *androidPlatformNativeInterface)
+{
+ if (androidPlatformNativeInterface && !m_instance) {
+ m_instance = new QAndroidPlatformTheme(androidPlatformNativeInterface);
+ }
+ return m_instance;
}
QAndroidPlatformTheme::QAndroidPlatformTheme(QAndroidPlatformNativeInterface *androidPlatformNativeInterface)
{
+ updateStyle();
+
+ androidPlatformNativeInterface->m_androidStyle = m_androidStyleData;
+
+ // default in case the style has not set a font
+ m_systemFont = QFont("Roboto"_L1, 14.0 * 100 / 72); // keep default size the same after changing from 100 dpi to 72 dpi
+}
+
+QAndroidPlatformTheme::~QAndroidPlatformTheme()
+{
+ m_instance = nullptr;
+}
+
+void QAndroidPlatformTheme::updateAppearance()
+{
+ updateStyle();
+ QWindowSystemInterface::handleThemeChange();
+}
+
+void QAndroidPlatformTheme::updateStyle()
+{
+ QColor windowText = Qt::black;
QColor background(229, 229, 229);
QColor light = background.lighter(150);
QColor mid(background.darker(130));
@@ -314,7 +358,27 @@ QAndroidPlatformTheme::QAndroidPlatformTheme(QAndroidPlatformNativeInterface *an
QColor highlight(148, 210, 231);
QColor disabledShadow = shadow.lighter(150);
- m_defaultPalette = QPalette(Qt::black,background,light,dark,mid,text,base);
+ if (appearance() == Qt::Appearance::Dark) {
+ // Colors were prepared based on Theme.DeviceDefault.DayNight
+ windowText = QColor(250, 250, 250);
+ background = QColor(48, 48, 48);
+ light = background.darker(150);
+ mid = background.lighter(130);
+ midLight = mid.darker(110);
+ base = background;
+ disabledBase = background;
+ dark = background.darker(150);
+ darkDisabled = dark.darker(110);
+ text = QColor(250, 250, 250);
+ highlightedText = QColor(250, 250, 250);
+ disabledText = QColor(96, 96, 96);
+ button = QColor(48, 48, 48);
+ shadow = QColor(32, 32, 32);
+ highlight = QColor(102, 178, 204);
+ disabledShadow = shadow.darker(150);
+ }
+
+ m_defaultPalette = QPalette(windowText,background,light,dark,mid,text,base);
m_defaultPalette.setBrush(QPalette::Midlight, midLight);
m_defaultPalette.setBrush(QPalette::Button, button);
m_defaultPalette.setBrush(QPalette::Shadow, shadow);
@@ -330,12 +394,9 @@ QAndroidPlatformTheme::QAndroidPlatformTheme(QAndroidPlatformNativeInterface *an
m_defaultPalette.setBrush(QPalette::Active, QPalette::Highlight, highlight);
m_defaultPalette.setBrush(QPalette::Inactive, QPalette::Highlight, highlight);
m_defaultPalette.setBrush(QPalette::Disabled, QPalette::Highlight, highlight.lighter(150));
- m_androidStyleData = loadAndroidStyle(&m_defaultPalette);
- QGuiApplication::setPalette(m_defaultPalette);
- androidPlatformNativeInterface->m_androidStyle = m_androidStyleData;
- // default in case the style has not set a font
- m_systemFont = QFont("Roboto"_L1, 14.0 * 100 / 72); // keep default size the same after changing from 100 dpi to 72 dpi
+ loadAndroidStyle(&m_defaultPalette, m_androidStyleData);
+ QGuiApplication::setPalette(m_defaultPalette);
}
QPlatformMenuBar *QAndroidPlatformTheme::createPlatformMenuBar() const
diff --git a/src/plugins/platforms/android/qandroidplatformtheme.h b/src/plugins/platforms/android/qandroidplatformtheme.h
index 0fc3c152c5..38e653ab71 100644
--- a/src/plugins/platforms/android/qandroidplatformtheme.h
+++ b/src/plugins/platforms/android/qandroidplatformtheme.h
@@ -30,7 +30,9 @@ class QAndroidPlatformNativeInterface;
class QAndroidPlatformTheme: public QPlatformTheme
{
public:
- QAndroidPlatformTheme(QAndroidPlatformNativeInterface * androidPlatformNativeInterface);
+ ~QAndroidPlatformTheme();
+ void updateAppearance();
+ void updateStyle();
QPlatformMenuBar *createPlatformMenuBar() const override;
QPlatformMenu *createPlatformMenu() const override;
QPlatformMenuItem *createPlatformMenuItem() const override;
@@ -43,8 +45,12 @@ public:
bool usePlatformNativeDialog(DialogType type) const override;
QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override;
+ static QAndroidPlatformTheme *instance(
+ QAndroidPlatformNativeInterface * androidPlatformNativeInterface = nullptr);
private:
+ QAndroidPlatformTheme(QAndroidPlatformNativeInterface * androidPlatformNativeInterface);
+ static QAndroidPlatformTheme * m_instance;
std::shared_ptr<AndroidStyle> m_androidStyleData;
QPalette m_defaultPalette;
QFont m_systemFont;