summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoFontScaleListener.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoFontScaleListener.java')
-rw-r--r--mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoFontScaleListener.java172
1 files changed, 172 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoFontScaleListener.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoFontScaleListener.java
new file mode 100644
index 0000000000..ec53d2803a
--- /dev/null
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoFontScaleListener.java
@@ -0,0 +1,172 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.geckoview;
+
+import android.annotation.SuppressLint;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.provider.Settings;
+import android.util.Log;
+import androidx.annotation.UiThread;
+import org.mozilla.gecko.util.ThreadUtils;
+
+/**
+ * A class that automatically adjusts font size settings for web content in Gecko in accordance with
+ * the device's OS font scale setting.
+ *
+ * @see android.provider.Settings.System#FONT_SCALE
+ */
+/* package */ final class GeckoFontScaleListener extends ContentObserver {
+ private static final String LOGTAG = "GeckoFontScaleListener";
+
+ private static final float DEFAULT_FONT_SCALE = 1.0f;
+
+ // We're referencing the *application* context, so this is in fact okay.
+ @SuppressLint("StaticFieldLeak")
+ private static final GeckoFontScaleListener sInstance = new GeckoFontScaleListener();
+
+ private Context mApplicationContext;
+ private GeckoRuntimeSettings mSettings;
+
+ private boolean mAttached;
+ private boolean mEnabled;
+ private boolean mRunning;
+
+ private float mPrevGeckoFontScale;
+
+ public static GeckoFontScaleListener getInstance() {
+ return sInstance;
+ }
+
+ private GeckoFontScaleListener() {
+ // Ensure the ContentObserver callback runs on the UI thread.
+ super(ThreadUtils.getUiHandler());
+ }
+
+ /**
+ * Prepare the GeckoFontScaleListener for usage. If it has been previously enabled, it will now
+ * start actively working.
+ */
+ public void attachToContext(final Context context, final GeckoRuntimeSettings settings) {
+ ThreadUtils.assertOnUiThread();
+
+ if (mAttached) {
+ Log.w(LOGTAG, "Already attached!");
+ return;
+ }
+
+ mAttached = true;
+ mSettings = settings;
+ mApplicationContext = context.getApplicationContext();
+ onEnabledChange();
+ }
+
+ /**
+ * Detaches the context and also stops the GeckoFontScaleListener if it was previously enabled.
+ * This will also restore the previously used font size settings.
+ */
+ public void detachFromContext() {
+ ThreadUtils.assertOnUiThread();
+
+ if (!mAttached) {
+ Log.w(LOGTAG, "Already detached!");
+ return;
+ }
+
+ stop();
+ mApplicationContext = null;
+ mSettings = null;
+ mAttached = false;
+ }
+
+ /**
+ * Controls whether the GeckoFontScaleListener should automatically adjust font sizes for web
+ * content in Gecko. When disabling, this will restore the previously used font size settings.
+ *
+ * <p>This method can be called at any time, but the GeckoFontScaleListener won't start actively
+ * adjusting font sizes until it has been attached to a context.
+ *
+ * @param enabled True if automatic font size setting should be enabled.
+ */
+ public void setEnabled(final boolean enabled) {
+ ThreadUtils.assertOnUiThread();
+ mEnabled = enabled;
+ onEnabledChange();
+ }
+
+ /**
+ * Get whether the GeckoFontScaleListener is currently enabled.
+ *
+ * @return True if the GeckoFontScaleListener is currently enabled.
+ */
+ public boolean getEnabled() {
+ return mEnabled;
+ }
+
+ private void onEnabledChange() {
+ if (!mAttached) {
+ return;
+ }
+
+ if (mEnabled) {
+ start();
+ } else {
+ stop();
+ }
+ }
+
+ private void start() {
+ if (mRunning) {
+ return;
+ }
+
+ mPrevGeckoFontScale = mSettings.getFontSizeFactor();
+ final ContentResolver contentResolver = mApplicationContext.getContentResolver();
+ final Uri fontSizeSetting = Settings.System.getUriFor(Settings.System.FONT_SCALE);
+ contentResolver.registerContentObserver(fontSizeSetting, false, this);
+ onSystemFontScaleChange(contentResolver, false);
+
+ mRunning = true;
+ }
+
+ private void stop() {
+ if (!mRunning) {
+ return;
+ }
+
+ final ContentResolver contentResolver = mApplicationContext.getContentResolver();
+ contentResolver.unregisterContentObserver(this);
+ onSystemFontScaleChange(contentResolver, /*stopping*/ true);
+
+ mRunning = false;
+ }
+
+ private void onSystemFontScaleChange(
+ final ContentResolver contentResolver, final boolean stopping) {
+ float fontScale;
+
+ if (!stopping) { // Either we were enabled, or else the system font scale changed.
+ fontScale =
+ Settings.System.getFloat(contentResolver, Settings.System.FONT_SCALE, DEFAULT_FONT_SCALE);
+ // Older Android versions don't sanitize the FONT_SCALE value. See Bug 1656078.
+ if (fontScale < 0) {
+ fontScale = DEFAULT_FONT_SCALE;
+ }
+ } else { // We were turned off.
+ fontScale = mPrevGeckoFontScale;
+ }
+
+ mSettings.setFontSizeFactorInternal(fontScale);
+ }
+
+ @UiThread // See constructor.
+ @Override
+ public void onChange(final boolean selfChange) {
+ onSystemFontScaleChange(mApplicationContext.getContentResolver(), false);
+ }
+}