diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSystemStateListener.java | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSystemStateListener.java')
-rw-r--r-- | mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSystemStateListener.java | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSystemStateListener.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSystemStateListener.java new file mode 100644 index 0000000000..6a71eff1fe --- /dev/null +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSystemStateListener.java @@ -0,0 +1,185 @@ +/* -*- 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.gecko; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.Configuration; +import android.database.ContentObserver; +import android.hardware.input.InputManager; +import android.net.Uri; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; +import android.util.Log; +import android.view.InputDevice; +import androidx.annotation.RequiresApi; +import org.mozilla.gecko.annotation.WrapForJNI; +import org.mozilla.gecko.util.InputDeviceUtils; +import org.mozilla.gecko.util.ThreadUtils; + +public class GeckoSystemStateListener implements InputManager.InputDeviceListener { + private static final String LOGTAG = "SystemStateListener"; + + private static final GeckoSystemStateListener listenerInstance = new GeckoSystemStateListener(); + + private boolean mInitialized; + private ContentObserver mContentObserver; + private static Context sApplicationContext; + private InputManager mInputManager; + private boolean mIsNightMode; + + public static GeckoSystemStateListener getInstance() { + return listenerInstance; + } + + private GeckoSystemStateListener() {} + + public synchronized void initialize(final Context context) { + if (mInitialized) { + Log.w(LOGTAG, "Already initialized!"); + return; + } + mInputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE); + mInputManager.registerInputDeviceListener(listenerInstance, ThreadUtils.getUiHandler()); + + sApplicationContext = context; + final ContentResolver contentResolver = sApplicationContext.getContentResolver(); + final Uri animationSetting = Settings.System.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE); + mContentObserver = + new ContentObserver(new Handler(Looper.getMainLooper())) { + @Override + public void onChange(final boolean selfChange) { + onDeviceChanged(); + } + }; + contentResolver.registerContentObserver(animationSetting, false, mContentObserver); + + final Uri invertSetting = + Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); + contentResolver.registerContentObserver(invertSetting, false, mContentObserver); + + mIsNightMode = + (sApplicationContext.getResources().getConfiguration().uiMode + & Configuration.UI_MODE_NIGHT_MASK) + == Configuration.UI_MODE_NIGHT_YES; + + mInitialized = true; + } + + public synchronized void shutdown() { + if (!mInitialized) { + Log.w(LOGTAG, "Already shut down!"); + return; + } + + if (mInputManager != null) { + Log.e(LOGTAG, "mInputManager should be valid!"); + return; + } + + mInputManager.unregisterInputDeviceListener(listenerInstance); + + final ContentResolver contentResolver = sApplicationContext.getContentResolver(); + contentResolver.unregisterContentObserver(mContentObserver); + + mInitialized = false; + mInputManager = null; + mContentObserver = null; + } + + @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) + @WrapForJNI(calledFrom = "gecko") + /** + * For prefers-reduced-motion media queries feature. + * + * <p>Uses `Settings.Global` which was introduced in API version 17. + */ + private static boolean prefersReducedMotion() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + return false; + } + + final ContentResolver contentResolver = sApplicationContext.getContentResolver(); + + return Settings.Global.getFloat(contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1) + == 0.0f; + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @WrapForJNI(calledFrom = "gecko") + /** + * For inverted-colors queries feature. + * + * <p>Uses `Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED` which was introduced in API + * version 21. + */ + private static boolean isInvertedColors() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + return false; + } + + final ContentResolver contentResolver = sApplicationContext.getContentResolver(); + + return Settings.Secure.getInt( + contentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0) + == 1; + } + + /** For prefers-color-scheme media queries feature. */ + public boolean isNightMode() { + return mIsNightMode; + } + + public void updateNightMode(final int newUIMode) { + final boolean isNightMode = + (newUIMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; + if (isNightMode == mIsNightMode) { + return; + } + mIsNightMode = isNightMode; + onDeviceChanged(); + } + + @WrapForJNI(stubName = "OnDeviceChanged", calledFrom = "any", dispatchTo = "gecko") + private static native void nativeOnDeviceChanged(); + + public static void onDeviceChanged() { + if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) { + nativeOnDeviceChanged(); + } else { + GeckoThread.queueNativeCallUntil( + GeckoThread.State.PROFILE_READY, GeckoSystemStateListener.class, "nativeOnDeviceChanged"); + } + } + + private void notifyDeviceChanged(final int deviceId) { + final InputDevice device = InputDevice.getDevice(deviceId); + if (device == null || !InputDeviceUtils.isPointerTypeDevice(device)) { + return; + } + onDeviceChanged(); + } + + @Override + public void onInputDeviceAdded(final int deviceId) { + notifyDeviceChanged(deviceId); + } + + @Override + public void onInputDeviceRemoved(final int deviceId) { + // Call onDeviceChanged directly without checking device source types + // since we can no longer get a valid `InputDevice` in the case of + // device removal. + onDeviceChanged(); + } + + @Override + public void onInputDeviceChanged(final int deviceId) { + notifyDeviceChanged(deviceId); + } +} |