From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../mozilla/gecko/GeckoSystemStateListener.java | 185 +++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSystemStateListener.java (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSystemStateListener.java') 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. + * + *

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. + * + *

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); + } +} -- cgit v1.2.3