summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Aurélien Pomini <pomini@google.com> 2023-03-08 11:57:11 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-03-08 11:57:11 +0000
commit91f654bdc9c369ff383be04c74eb4ea965d9994b (patch)
tree85a990a693e1edd690561d62bff7c0afaac2b0b6
parent6c81f3c188cbedc92417ea93bfb132075ac7a940 (diff)
parent55c217124a13d45af89d82c8a39a593f852bafb6 (diff)
Merge changes from topic "move_contrast_api" into udc-dev
* changes: Move contrast API: adapt ThemeOverlayController Add the contrast API to UiModeManager Revert "Add API to get/listen to the color contrast setting"
-rw-r--r--core/api/current.txt14
-rw-r--r--core/java/android/app/IUiModeManager.aidl11
-rw-r--r--core/java/android/app/IUiModeManagerCallback.aidl27
-rw-r--r--core/java/android/app/UiModeManager.java171
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java119
-rw-r--r--core/java/android/view/accessibility/IAccessibilityManager.aidl2
-rw-r--r--core/java/android/view/accessibility/IAccessibilityManagerClient.aidl2
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java12
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java51
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java22
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java67
12 files changed, 301 insertions, 219 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 37480520529b..6f206eee3786 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -7398,12 +7398,15 @@ package android.app {
}
public class UiModeManager {
+ method public void addContrastChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.UiModeManager.ContrastChangeListener);
method public void disableCarMode(int);
method public void enableCarMode(int);
+ method @FloatRange(from=-1.0F, to=1.0f) public float getContrast();
method public int getCurrentModeType();
method @NonNull public java.time.LocalTime getCustomNightModeEnd();
method @NonNull public java.time.LocalTime getCustomNightModeStart();
method public int getNightMode();
+ method public void removeContrastChangeListener(@NonNull android.app.UiModeManager.ContrastChangeListener);
method public void setApplicationNightMode(int);
method public void setCustomNightModeEnd(@NonNull java.time.LocalTime);
method public void setCustomNightModeStart(@NonNull java.time.LocalTime);
@@ -7421,6 +7424,10 @@ package android.app {
field public static final int MODE_NIGHT_YES = 2; // 0x2
}
+ public static interface UiModeManager.ContrastChangeListener {
+ method public void onContrastChanged(@FloatRange(from=-1.0F, to=1.0f) float);
+ }
+
public final class VoiceInteractor {
method public android.app.VoiceInteractor.Request getActiveRequest(String);
method public android.app.VoiceInteractor.Request[] getActiveRequests();
@@ -54161,14 +54168,12 @@ package android.view.accessibility {
method public void addAudioDescriptionRequestedChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.accessibility.AccessibilityManager.AudioDescriptionRequestedChangeListener);
method public boolean addTouchExplorationStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
method public void addTouchExplorationStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, @Nullable android.os.Handler);
- method public void addUiContrastChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.accessibility.AccessibilityManager.UiContrastChangeListener);
method @ColorInt public int getAccessibilityFocusColor();
method public int getAccessibilityFocusStrokeWidth();
method @Deprecated public java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
method public int getRecommendedTimeoutMillis(int, int);
- method @FloatRange(from=-1.0F, to=1.0f) public float getUiContrast();
method public void interrupt();
method public static boolean isAccessibilityButtonSupported();
method public boolean isAudioDescriptionRequested();
@@ -54180,7 +54185,6 @@ package android.view.accessibility {
method public boolean removeAccessibilityStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
method public boolean removeAudioDescriptionRequestedChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AudioDescriptionRequestedChangeListener);
method public boolean removeTouchExplorationStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
- method public void removeUiContrastChangeListener(@NonNull android.view.accessibility.AccessibilityManager.UiContrastChangeListener);
method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
field public static final int FLAG_CONTENT_CONTROLS = 4; // 0x4
field public static final int FLAG_CONTENT_ICONS = 1; // 0x1
@@ -54203,10 +54207,6 @@ package android.view.accessibility {
method public void onTouchExplorationStateChanged(boolean);
}
- public static interface AccessibilityManager.UiContrastChangeListener {
- method public void onUiContrastChanged(@FloatRange(from=-1.0F, to=1.0f) float);
- }
-
public class AccessibilityNodeInfo implements android.os.Parcelable {
ctor public AccessibilityNodeInfo();
ctor public AccessibilityNodeInfo(@NonNull android.view.View);
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index 2242224b2769..2345c27a4587 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -17,6 +17,7 @@
package android.app;
import android.app.IOnProjectionStateChangedListener;
+import android.app.IUiModeManagerCallback;
/**
* Interface used to control special UI modes.
@@ -24,6 +25,11 @@ import android.app.IOnProjectionStateChangedListener;
*/
interface IUiModeManager {
/**
+ * @hide
+ */
+ void addCallback(IUiModeManagerCallback callback);
+
+ /**
* Enables the car mode. Only the system can do this.
* @hide
*/
@@ -173,4 +179,9 @@ interface IUiModeManager {
* Returns currently set projection types.
*/
int getActiveProjectionTypes();
+
+ /**
+ * Returns the contrast for the current user
+ */
+ float getContrast();
}
diff --git a/core/java/android/app/IUiModeManagerCallback.aidl b/core/java/android/app/IUiModeManagerCallback.aidl
new file mode 100644
index 000000000000..47c18a8bd3cb
--- /dev/null
+++ b/core/java/android/app/IUiModeManagerCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+/**
+* Implemented by the UiModeManager client to receive information about changes from the service.
+* This is a oneway interface since the server should not block waiting for the client.
+*
+* @hide
+*/
+oneway interface IUiModeManagerCallback {
+ void notifyContrastChanged(float contrast);
+}
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index ecab37db4ba7..d90257a69281 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -17,6 +17,7 @@
package android.app;
import android.annotation.CallbackExecutor;
+import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -34,6 +35,7 @@ import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -43,10 +45,13 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.time.LocalTime;
+import java.util.Comparator;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
+import java.util.stream.Stream;
/**
* This class provides access to the system uimode services. These services
@@ -72,6 +77,10 @@ import java.util.concurrent.Executor;
*/
@SystemService(Context.UI_MODE_SERVICE)
public class UiModeManager {
+
+ private static final String TAG = "UiModeManager";
+
+
/**
* A listener with a single method that is invoked whenever the packages projecting using the
* {@link ProjectionType}s for which it is registered change.
@@ -91,7 +100,20 @@ public class UiModeManager {
@NonNull Set<String> packageNames);
}
- private static final String TAG = "UiModeManager";
+ /**
+ * Listener for the UI contrast. To listen for changes to
+ * the UI contrast on the device, implement this interface and
+ * register it with the system by calling {@link #addContrastChangeListener}.
+ */
+ public interface ContrastChangeListener {
+
+ /**
+ * Called when the color contrast enabled state changes.
+ *
+ * @param contrast The color contrast as in {@link #getContrast}
+ */
+ void onContrastChanged(@FloatRange(from = -1.0f, to = 1.0f) float contrast);
+ }
/**
* Broadcast sent when the device's UI has switched to car mode, either
@@ -319,6 +341,95 @@ public class UiModeManager {
mOnProjectionStateChangedListenerResourceManager =
new OnProjectionStateChangedListenerResourceManager();
+ /**
+ * Define constants and conversions between {@link ContrastLevel}s and contrast values.
+ * <p>
+ * Contrast values are floats defined in [-1, 1], as defined in {@link #getContrast}.
+ * This is the official data type for contrast;
+ * all methods from the public API return contrast values.
+ * </p>
+ * <p>
+ * {@code ContrastLevel}, on the other hand, is an internal-only enumeration of contrasts that
+ * can be set from the system ui. Each {@code ContrastLevel} has an associated contrast value.
+ * </p>
+ * <p>
+ * Currently, a user chan chose from three contrast levels:
+ * <ul>
+ * <li>{@link #CONTRAST_LEVEL_STANDARD}, corresponding to the default contrast value 0f</li>
+ * <li>{@link #CONTRAST_LEVEL_MEDIUM}, corresponding to the contrast value 0.5f</li>
+ * <li>{@link #CONTRAST_LEVEL_HIGH}, corresponding to the maximum contrast value 1f</li>
+ * </ul>
+ * </p>
+ *
+ * @hide
+ */
+ public static class ContrastUtils {
+
+ private static final float CONTRAST_MIN_VALUE = -1f;
+ private static final float CONTRAST_MAX_VALUE = 1f;
+ public static final float CONTRAST_DEFAULT_VALUE = 0f;
+
+ @IntDef(flag = true, prefix = { "CONTRAST_LEVEL_" }, value = {
+ CONTRAST_LEVEL_STANDARD,
+ CONTRAST_LEVEL_MEDIUM,
+ CONTRAST_LEVEL_HIGH
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ContrastLevel {}
+
+ public static final int CONTRAST_LEVEL_STANDARD = 0;
+ public static final int CONTRAST_LEVEL_MEDIUM = 1;
+ public static final int CONTRAST_LEVEL_HIGH = 2;
+
+ private static Stream<Integer> allContrastLevels() {
+ return Stream.of(CONTRAST_LEVEL_STANDARD, CONTRAST_LEVEL_MEDIUM, CONTRAST_LEVEL_HIGH);
+ }
+
+ /**
+ * Convert a contrast value in [-1, 1] to its associated {@link ContrastLevel}
+ */
+ public static @ContrastLevel int toContrastLevel(float contrast) {
+ if (contrast < CONTRAST_MIN_VALUE || contrast > CONTRAST_MAX_VALUE) {
+ throw new IllegalArgumentException("contrast values should be in [-1, 1]");
+ }
+ return allContrastLevels().min(Comparator.comparingDouble(contrastLevel ->
+ Math.abs(contrastLevel - 2 * contrast))).orElseThrow();
+ }
+
+ /**
+ * Convert a {@link ContrastLevel} to its associated contrast value in [-1, 1]
+ */
+ public static float fromContrastLevel(@ContrastLevel int contrastLevel) {
+ if (allContrastLevels().noneMatch(level -> level == contrastLevel)) {
+ throw new IllegalArgumentException("unrecognized contrast level: " + contrastLevel);
+ }
+ return contrastLevel / 2f;
+ }
+ }
+
+ /**
+ * Map that stores user provided {@link ContrastChangeListener} callbacks,
+ * and the executors on which these callbacks should be called.
+ */
+ private final ArrayMap<ContrastChangeListener, Executor>
+ mContrastChangeListeners = new ArrayMap<>();
+ private float mContrast;
+
+ private final IUiModeManagerCallback.Stub mCallback = new IUiModeManagerCallback.Stub() {
+ @Override
+ public void notifyContrastChanged(float contrast) {
+ final ArrayMap<ContrastChangeListener, Executor> listeners;
+ synchronized (mLock) {
+ // if value changed in the settings, update the cached value and notify listeners
+ if (Math.abs(mContrast - contrast) < 1e-10) return;
+ mContrast = contrast;
+ listeners = new ArrayMap<>(mContrastChangeListeners);
+ }
+ listeners.forEach((listener, executor) -> executor.execute(
+ () -> listener.onContrastChanged(mContrast)));
+ }
+ };
+
@UnsupportedAppUsage
/*package*/ UiModeManager() throws ServiceNotFoundException {
this(null /* context */);
@@ -328,6 +439,12 @@ public class UiModeManager {
mService = IUiModeManager.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.UI_MODE_SERVICE));
mContext = context;
+ try {
+ mService.addCallback(mCallback);
+ mContrast = mService.getContrast();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Setup failed: UiModeManagerService is dead", e);
+ }
}
/**
@@ -1067,4 +1184,56 @@ public class UiModeManager {
return mExecutorMap.get(innerListener);
}
}
+
+ /**
+ * Returns the color contrast for the user.
+ * <p>
+ * <strong>Note:</strong> You need to query this only if your application is
+ * doing its own rendering and does not rely on the material rendering pipeline.
+ * </p>
+ * @return The color contrast, float in [-1, 1] where
+ * <ul>
+ * <li> &nbsp; 0 corresponds to the default contrast </li>
+ * <li> -1 corresponds to the minimum contrast </li>
+ * <li> &nbsp; 1 corresponds to the maximum contrast </li>
+ * </ul>
+ *
+ *
+ *
+ */
+ @FloatRange(from = -1.0f, to = 1.0f)
+ public float getContrast() {
+ synchronized (mLock) {
+ return mContrast;
+ }
+ }
+
+ /**
+ * Registers a {@link ContrastChangeListener} for the current user.
+ *
+ * @param executor The executor on which the listener should be called back.
+ * @param listener The listener.
+ */
+ public void addContrastChangeListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull ContrastChangeListener listener) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(listener);
+ synchronized (mLock) {
+ mContrastChangeListeners.put(listener, executor);
+ }
+ }
+
+ /**
+ * Unregisters a {@link ContrastChangeListener} for the current user.
+ * If the listener was not registered, does nothing and returns.
+ *
+ * @param listener The listener to unregister.
+ */
+ public void removeContrastChangeListener(@NonNull ContrastChangeListener listener) {
+ Objects.requireNonNull(listener);
+ synchronized (mLock) {
+ mContrastChangeListeners.remove(listener);
+ }
+ }
}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 9504852f6e98..5ad2476930f1 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -25,7 +25,6 @@ import android.accessibilityservice.AccessibilityServiceInfo.FeedbackType;
import android.accessibilityservice.AccessibilityShortcutInfo;
import android.annotation.CallbackExecutor;
import android.annotation.ColorInt;
-import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -76,7 +75,6 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -140,21 +138,6 @@ public final class AccessibilityManager {
public static final int AUTOCLICK_DELAY_DEFAULT = 600;
/**
- * The contrast is defined as a float in [-1, 1], with a default value of 0.
- * @hide
- */
- public static final float CONTRAST_MIN_VALUE = -1f;
-
- /** @hide */
- public static final float CONTRAST_MAX_VALUE = 1f;
-
- /** @hide */
- public static final float CONTRAST_DEFAULT_VALUE = 0f;
-
- /** @hide */
- public static final float CONTRAST_NOT_SET = Float.MIN_VALUE;
-
- /**
* Activity action: Launch UI to manage which accessibility service or feature is assigned
* to the navigation bar Accessibility button.
* <p>
@@ -288,8 +271,6 @@ public final class AccessibilityManager {
@UnsupportedAppUsage(trackingBug = 123768939L)
boolean mIsHighTextContrastEnabled;
- private float mUiContrast;
-
boolean mIsAudioDescriptionByDefaultRequested;
// accessibility tracing state
@@ -314,9 +295,6 @@ public final class AccessibilityManager {
private final ArrayMap<HighTextContrastChangeListener, Handler>
mHighTextContrastStateChangeListeners = new ArrayMap<>();
- private final ArrayMap<UiContrastChangeListener, Executor>
- mUiContrastChangeListeners = new ArrayMap<>();
-
private final ArrayMap<AccessibilityServicesStateChangeListener, Executor>
mServicesStateChangeListeners = new ArrayMap<>();
@@ -390,7 +368,7 @@ public final class AccessibilityManager {
*
* @param manager The manager that is calling back
*/
- void onAccessibilityServicesStateChanged(@NonNull AccessibilityManager manager);
+ void onAccessibilityServicesStateChanged(@NonNull AccessibilityManager manager);
}
/**
@@ -412,21 +390,6 @@ public final class AccessibilityManager {
}
/**
- * Listener for the UI contrast. To listen for changes to
- * the UI contrast on the device, implement this interface and
- * register it with the system by calling {@link #addUiContrastChangeListener}.
- */
- public interface UiContrastChangeListener {
-
- /**
- * Called when the color contrast enabled state changes.
- *
- * @param uiContrast The color contrast as in {@link #getUiContrast}
- */
- void onUiContrastChanged(@FloatRange(from = -1.0f, to = 1.0f) float uiContrast);
- }
-
- /**
* Listener for the audio description by default state. To listen for
* changes to the audio description by default state on the device,
* implement this interface and register it with the system by calling
@@ -540,16 +503,6 @@ public final class AccessibilityManager {
updateFocusAppearanceLocked(strokeWidth, color);
}
}
-
- @Override
- public void setUiContrast(float contrast) {
- synchronized (mLock) {
- // if value changed in the settings, update the cached value and notify listeners
- if (Math.abs(mUiContrast - contrast) < 1e-10) return;
- mUiContrast = contrast;
- }
- mHandler.obtainMessage(MyCallback.MSG_NOTIFY_CONTRAST_CHANGED).sendToTarget();
- }
};
/**
@@ -720,7 +673,7 @@ public final class AccessibilityManager {
/**
* Returns if the high text contrast in the system is enabled.
* <p>
- * <strong>Note:</strong> You need to query this only if your application is
+ * <strong>Note:</strong> You need to query this only if you application is
* doing its own rendering and does not rely on the platform rendering pipeline.
* </p>
*
@@ -740,24 +693,6 @@ public final class AccessibilityManager {
}
/**
- * Returns the color contrast for the user.
- * <p>
- * <strong>Note:</strong> You need to query this only if your application is
- * doing its own rendering and does not rely on the platform rendering pipeline.
- * </p>
- * @return The color contrast, float in [-1, 1] where
- * 0 corresponds to the default contrast
- * -1 corresponds to the minimum contrast that the user can set
- * 1 corresponds to the maximum contrast that the user can set
- */
- @FloatRange(from = -1.0f, to = 1.0f)
- public float getUiContrast() {
- synchronized (mLock) {
- return mUiContrast;
- }
- }
-
- /**
* Sends an {@link AccessibilityEvent}.
*
* @param event The event to send.
@@ -1346,35 +1281,6 @@ public final class AccessibilityManager {
}
/**
- * Registers a {@link UiContrastChangeListener} for the current user.
- *
- * @param executor The executor on which the listener should be called back.
- * @param listener The listener.
- */
- public void addUiContrastChangeListener(
- @NonNull @CallbackExecutor Executor executor,
- @NonNull UiContrastChangeListener listener) {
- Objects.requireNonNull(executor);
- Objects.requireNonNull(listener);
- synchronized (mLock) {
- mUiContrastChangeListeners.put(listener, executor);
- }
- }
-
- /**
- * Unregisters a {@link UiContrastChangeListener} for the current user.
- * If the listener was not registered, does nothing and returns.
- *
- * @param listener The listener to unregister.
- */
- public void removeUiContrastChangeListener(@NonNull UiContrastChangeListener listener) {
- Objects.requireNonNull(listener);
- synchronized (mLock) {
- mUiContrastChangeListeners.remove(listener);
- }
- }
-
- /**
* Registers a {@link AudioDescriptionRequestedChangeListener}
* for changes in the audio description by default state of the system.
* The value could be read via {@link #isAudioDescriptionRequested}.
@@ -2232,7 +2138,6 @@ public final class AccessibilityManager {
mRelevantEventTypes = IntPair.second(userStateAndRelevantEvents);
updateUiTimeout(service.getRecommendedTimeoutMillis());
updateFocusAppearanceLocked(service.getFocusStrokeWidth(), service.getFocusColor());
- mUiContrast = service.getUiContrast();
mService = service;
} catch (RemoteException re) {
Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
@@ -2311,22 +2216,6 @@ public final class AccessibilityManager {
}
/**
- * Notifies the registered {@link UiContrastChangeListener}s if the value changed.
- */
- private void notifyUiContrastChanged() {
- final ArrayMap<UiContrastChangeListener, Executor> listeners;
- synchronized (mLock) {
- listeners = new ArrayMap<>(mUiContrastChangeListeners);
- }
-
- listeners.entrySet().forEach(entry -> {
- UiContrastChangeListener listener = entry.getKey();
- Executor executor = entry.getValue();
- executor.execute(() -> listener.onUiContrastChanged(mUiContrast));
- });
- }
-
- /**
* Notifies the registered {@link AudioDescriptionStateChangeListener}s.
*/
private void notifyAudioDescriptionbyDefaultStateChanged() {
@@ -2416,7 +2305,6 @@ public final class AccessibilityManager {
private final class MyCallback implements Handler.Callback {
public static final int MSG_SET_STATE = 1;
- public static final int MSG_NOTIFY_CONTRAST_CHANGED = 2;
@Override
public boolean handleMessage(Message message) {
@@ -2428,9 +2316,6 @@ public final class AccessibilityManager {
setStateLocked(state);
}
} break;
- case MSG_NOTIFY_CONTRAST_CHANGED: {
- notifyUiContrastChanged();
- }
}
return true;
}
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 1302421d0ce2..c8280583f35d 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -120,8 +120,6 @@ interface IAccessibilityManager {
// Used by UiAutomation for tests on the InputFilter
void injectInputEventToInputFilter(in InputEvent event);
- float getUiContrast();
-
boolean startFlashNotificationSequence(String opPkg, int reason, IBinder token);
boolean stopFlashNotificationSequence(String opPkg);
boolean startFlashNotificationEvent(String opPkg, int reason, String reasonPkg);
diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
index 931f862e581b..041399ccb8ec 100644
--- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
@@ -31,6 +31,4 @@ oneway interface IAccessibilityManagerClient {
void setRelevantEventTypes(int eventTypes);
void setFocusAppearance(int strokeWidth, int color);
-
- void setUiContrast(float contrast);
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 2ad3558fdb16..faae8df44ed9 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -29,6 +29,7 @@ import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_COLOR_INDEX
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_COLOR_SOURCE;
import static com.android.systemui.theme.ThemeOverlayApplier.TIMESTAMP_FIELD;
+import android.app.UiModeManager;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.app.WallpaperManager.OnColorsChangedListener;
@@ -54,7 +55,6 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
-import android.view.accessibility.AccessibilityManager;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -140,8 +140,8 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
private boolean mNeedsOverlayCreation;
// Dominant color extracted from wallpaper, NOT the color used on the overlay
protected int mMainWallpaperColor = Color.TRANSPARENT;
- // UI contrast as reported by AccessibilityManager
- private float mUiContrast = 0;
+ // UI contrast as reported by UiModeManager
+ private float mContrast = 0;
// Theme variant: Vibrant, Tonal, Expressive, etc
@VisibleForTesting
protected Style mThemeStyle = Style.TONAL_SPOT;
@@ -158,7 +158,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
private final SparseArray<WallpaperColors> mDeferredWallpaperColors = new SparseArray<>();
private final SparseIntArray mDeferredWallpaperColorsFlags = new SparseIntArray();
private final WakefulnessLifecycle mWakefulnessLifecycle;
- private final AccessibilityManager mAccessibilityManager;
+ private final UiModeManager mUiModeManager;
private DynamicScheme mDynamicSchemeDark;
private DynamicScheme mDynamicSchemeLight;
@@ -392,7 +392,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
FeatureFlags featureFlags,
@Main Resources resources,
WakefulnessLifecycle wakefulnessLifecycle,
- AccessibilityManager accessibilityManager) {
+ UiModeManager uiModeManager) {
mContext = context;
mIsMonochromaticEnabled = featureFlags.isEnabled(Flags.MONOCHROMATIC_THEME);
mIsMonetEnabled = featureFlags.isEnabled(Flags.MONET);
@@ -408,7 +408,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
mUserTracker = userTracker;
mResources = resources;
mWakefulnessLifecycle = wakefulnessLifecycle;
- mAccessibilityManager = accessibilityManager;
+ mUiModeManager = uiModeManager;
dumpManager.registerDumpable(TAG, this);
}
@@ -445,9 +445,9 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
}
},
UserHandle.USER_ALL);
- mUiContrast = mAccessibilityManager.getUiContrast();
- mAccessibilityManager.addUiContrastChangeListener(mMainExecutor, uiContrast -> {
- mUiContrast = uiContrast;
+ mContrast = mUiModeManager.getContrast();
+ mUiModeManager.addContrastChangeListener(mMainExecutor, contrast -> {
+ mContrast = contrast;
// Force reload so that we update even when the main color has not changed
reevaluateSystemTheme(true /* forceReload */);
});
@@ -586,9 +586,9 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
mSecondaryOverlay = createAccentOverlay();
mDynamicSchemeDark = dynamicSchemeFromStyle(
- mThemeStyle, color, true /* isDark */, mUiContrast);
+ mThemeStyle, color, true /* isDark */, mContrast);
mDynamicSchemeLight = dynamicSchemeFromStyle(
- mThemeStyle, color, false /* isDark */, mUiContrast);
+ mThemeStyle, color, false /* isDark */, mContrast);
mDynamicOverlay = createDynamicOverlay();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index f9b5767bf53c..17b5e0546eca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -33,6 +33,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import android.app.UiModeManager;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
@@ -47,7 +48,6 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
-import android.view.accessibility.AccessibilityManager;
import androidx.annotation.VisibleForTesting;
import androidx.test.filters.SmallTest;
@@ -116,7 +116,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
@Mock
private WakefulnessLifecycle mWakefulnessLifecycle;
@Mock
- private AccessibilityManager mAccessibilityManager;
+ private UiModeManager mUiModeManager;
@Captor
private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiver;
@Captor
@@ -135,7 +135,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
when(mFeatureFlags.isEnabled(Flags.MONET)).thenReturn(true);
when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
- when(mAccessibilityManager.getUiContrast()).thenReturn(0.5f);
+ when(mUiModeManager.getContrast()).thenReturn(0.5f);
when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
when(mResources.getColor(eq(android.R.color.system_accent1_500), any()))
.thenReturn(Color.RED);
@@ -151,7 +151,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
mBroadcastDispatcher, mBgHandler, mMainExecutor, mBgExecutor, mThemeOverlayApplier,
mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle,
- mAccessibilityManager) {
+ mUiModeManager) {
@VisibleForTesting
protected boolean isNightMode() {
return false;
@@ -733,7 +733,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier,
mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle,
- mAccessibilityManager) {
+ mUiModeManager) {
@VisibleForTesting
protected boolean isNightMode() {
return false;
@@ -773,7 +773,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier,
mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle,
- mAccessibilityManager) {
+ mUiModeManager) {
@VisibleForTesting
protected boolean isNightMode() {
return false;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 7fba72b74e8d..6503595f2f62 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -26,11 +26,8 @@ import static android.accessibilityservice.AccessibilityTrace.FLAGS_USER_BROADCA
import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION;
import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED;
-import static android.provider.Settings.Secure.CONTRAST_LEVEL;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
-import static android.view.accessibility.AccessibilityManager.CONTRAST_DEFAULT_VALUE;
-import static android.view.accessibility.AccessibilityManager.CONTRAST_NOT_SET;
import static android.view.accessibility.AccessibilityManager.FlashNotificationReason;
import static android.view.accessibility.AccessibilityManager.ShortcutType;
@@ -1997,16 +1994,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
return false;
}
- private boolean readUiContrastLocked(AccessibilityUserState userState) {
- float contrast = Settings.Secure.getFloatForUser(mContext.getContentResolver(),
- CONTRAST_LEVEL, CONTRAST_DEFAULT_VALUE, userState.mUserId);
- if (Math.abs(userState.getUiContrastLocked() - contrast) >= 1e-10) {
- userState.setUiContrastLocked(contrast);
- return true;
- }
- return false;
- }
-
/**
* Performs {@link AccessibilityService}s delayed notification. The delay is configurable
* and denotes the period after the last event before notifying the service.
@@ -2676,7 +2663,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
somethingChanged |= readMagnificationCapabilitiesLocked(userState);
somethingChanged |= readMagnificationFollowTypingLocked(userState);
somethingChanged |= readAlwaysOnMagnificationLocked(userState);
- somethingChanged |= readUiContrastLocked(userState);
return somethingChanged;
}
@@ -3851,19 +3837,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
return mProxyManager.isProxyed(displayId);
}
- @Override public float getUiContrast() {
- if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
- mTraceManager.logTrace(LOG_TAG + ".getUiContrast", FLAGS_ACCESSIBILITY_MANAGER);
- }
- synchronized (mLock) {
- AccessibilityUserState userState = getCurrentUserStateLocked();
- float contrast = userState.getUiContrastLocked();
- if (contrast != CONTRAST_NOT_SET) return contrast;
- readUiContrastLocked(userState);
- return userState.getUiContrastLocked();
- }
- }
-
@Override
public boolean startFlashNotificationSequence(String opPkg,
@FlashNotificationReason int reason, IBinder token) {
@@ -4350,9 +4323,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private final Uri mAlwaysOnMagnificationUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED);
- private final Uri mUiContrastUri = Settings.Secure.getUriFor(
- CONTRAST_LEVEL);
-
public AccessibilityContentObserver(Handler handler) {
super(handler);
}
@@ -4395,8 +4365,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mMagnificationFollowTypingUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
mAlwaysOnMagnificationUri, false, this, UserHandle.USER_ALL);
- contentResolver.registerContentObserver(
- mUiContrastUri, false, this, UserHandle.USER_ALL);
}
@Override
@@ -4468,10 +4436,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
readMagnificationFollowTypingLocked(userState);
} else if (mAlwaysOnMagnificationUri.equals(uri)) {
readAlwaysOnMagnificationLocked(userState);
- } else if (mUiContrastUri.equals(uri)) {
- if (readUiContrastLocked(userState)) {
- updateUiContrastLocked(userState);
- }
}
}
}
@@ -4788,22 +4752,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
userState.getFocusColorLocked());
}));
});
- }
- private void updateUiContrastLocked(AccessibilityUserState userState) {
- if (userState.mUserId != mCurrentUserId) {
- return;
- }
- if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) {
- mTraceManager.logTrace(LOG_TAG + ".updateUiContrastLocked",
- FLAGS_ACCESSIBILITY_SERVICE_CLIENT, "userState=" + userState);
- }
- float contrast = userState.getUiContrastLocked();
- mMainHandler.post(() -> {
- broadcastToClients(userState, ignoreRemoteException(client -> {
- client.mCallback.setUiContrast(contrast);
- }));
- });
}
public AccessibilityTraceManager getTraceManager() {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 1c9ce3c82735..3b169f8f715e 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -26,8 +26,6 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
-import static android.view.accessibility.AccessibilityManager.CONTRAST_DEFAULT_VALUE;
-import static android.view.accessibility.AccessibilityManager.CONTRAST_NOT_SET;
import static android.view.accessibility.AccessibilityManager.ShortcutType;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
@@ -147,8 +145,6 @@ class AccessibilityUserState {
private final int mFocusStrokeWidthDefaultValue;
// The default value of the focus color.
private final int mFocusColorDefaultValue;
- /** The color contrast in [-1, 1] */
- private float mUiContrast = CONTRAST_DEFAULT_VALUE;
private Context mContext;
@@ -224,7 +220,6 @@ class AccessibilityUserState {
mFocusColor = mFocusColorDefaultValue;
mMagnificationFollowTypingEnabled = true;
mAlwaysOnMagnificationEnabled = false;
- mUiContrast = CONTRAST_NOT_SET;
}
void addServiceLocked(AccessibilityServiceConnection serviceConnection) {
@@ -1001,7 +996,6 @@ class AccessibilityUserState {
return mFocusColor;
}
-
/**
* Sets the stroke width and color of the focus rectangle.
*
@@ -1027,20 +1021,4 @@ class AccessibilityUserState {
}
return false;
}
-
- /**
- * Get the color contrast
- * @return color contrast in [-1, 1]
- */
- public float getUiContrastLocked() {
- return mUiContrast;
- }
-
- /**
- * Set the color contrast
- * @param contrast the new color contrast in [-1, 1]
- */
- public void setUiContrastLocked(float contrast) {
- mUiContrast = contrast;
- }
}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 5d46de335781..7c32627dd1b1 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.app.UiModeManager.ContrastUtils.CONTRAST_DEFAULT_VALUE;
import static android.app.UiModeManager.DEFAULT_PRIORITY;
import static android.app.UiModeManager.MODE_NIGHT_AUTO;
import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
@@ -27,8 +28,11 @@ import static android.app.UiModeManager.MODE_NIGHT_YES;
import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE;
import static android.app.UiModeManager.PROJECTION_TYPE_NONE;
import static android.os.UserHandle.USER_SYSTEM;
+import static android.provider.Settings.Secure.CONTRAST_LEVEL;
import static android.util.TimeUtils.isTimeBetween;
+import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
+
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -38,6 +42,7 @@ import android.app.ActivityTaskManager;
import android.app.AlarmManager;
import android.app.IOnProjectionStateChangedListener;
import android.app.IUiModeManager;
+import android.app.IUiModeManagerCallback;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -71,6 +76,7 @@ import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.provider.Settings;
import android.provider.Settings.Secure;
import android.service.dreams.Sandman;
import android.service.vr.IVrManager;
@@ -193,12 +199,19 @@ final class UiModeManagerService extends SystemService {
private PowerManagerInternal mLocalPowerManager;
@GuardedBy("mLock")
+ private final RemoteCallbackList<IUiModeManagerCallback> mUiModeManagerCallbacks =
+ new RemoteCallbackList<IUiModeManagerCallback>();
+
+ @GuardedBy("mLock")
@Nullable
private SparseArray<List<ProjectionHolder>> mProjectionHolders;
@GuardedBy("mLock")
@Nullable
private SparseArray<RemoteCallbackList<IOnProjectionStateChangedListener>> mProjectionListeners;
+ @GuardedBy("mLock")
+ private final SparseArray<Float> mContrasts = new SparseArray<>();
+
public UiModeManagerService(Context context) {
this(context, /* setupWizardComplete= */ false, /* tm= */ null, new Injector());
}
@@ -352,6 +365,19 @@ final class UiModeManagerService extends SystemService {
}
};
+ private final ContentObserver mContrastObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ synchronized (mLock) {
+ if (updateContrastLocked()) {
+ float contrast = getContrastLocked();
+ mUiModeManagerCallbacks.broadcast(ignoreRemoteException(callback ->
+ callback.notifyContrastChanged(contrast)));
+ }
+ }
+ }
+ };
+
private void updateSystemProperties() {
int mode = Secure.getIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE,
mNightMode, 0);
@@ -407,6 +433,9 @@ final class UiModeManagerService extends SystemService {
context.getContentResolver()
.registerContentObserver(Secure.getUriFor(Secure.UI_NIGHT_MODE),
false, mDarkThemeObserver, 0);
+ context.getContentResolver().registerContentObserver(
+ Secure.getUriFor(Secure.CONTRAST_LEVEL), false,
+ mContrastObserver, UserHandle.USER_ALL);
context.registerReceiver(mDockModeReceiver,
new IntentFilter(Intent.ACTION_DOCK_EVENT));
IntentFilter batteryFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
@@ -634,6 +663,13 @@ final class UiModeManagerService extends SystemService {
private final IUiModeManager.Stub mService = new IUiModeManager.Stub() {
@Override
+ public void addCallback(IUiModeManagerCallback callback) {
+ synchronized (mLock) {
+ mUiModeManagerCallbacks.register(callback);
+ }
+ }
+
+ @Override
public void enableCarMode(@UiModeManager.EnableCarMode int flags,
@IntRange(from = 0) int priority, String callingPackage) {
if (isUiModeLocked()) {
@@ -1132,6 +1168,13 @@ final class UiModeManagerService extends SystemService {
}
}
}
+
+ @Override
+ public float getContrast() {
+ synchronized (mLock) {
+ return getContrastLocked();
+ }
+ }
};
private void enforceProjectionTypePermissions(@UiModeManager.ProjectionType int p) {
@@ -1214,6 +1257,30 @@ final class UiModeManagerService extends SystemService {
}
}
+ /**
+ * Return the contrast for the current user. If not cached, fetch it from the settings.
+ */
+ @GuardedBy("mLock")
+ private float getContrastLocked() {
+ if (!mContrasts.contains(mCurrentUser)) updateContrastLocked();
+ return mContrasts.get(mCurrentUser);
+ }
+
+ /**
+ * Read the contrast setting for the current user and update {@link #mContrasts}
+ * if the contrast changed. Returns true if {@link #mContrasts} was updated.
+ */
+ @GuardedBy("mLock")
+ private boolean updateContrastLocked() {
+ float contrast = Settings.Secure.getFloatForUser(getContext().getContentResolver(),
+ CONTRAST_LEVEL, CONTRAST_DEFAULT_VALUE, mCurrentUser);
+ if (Math.abs(mContrasts.get(mCurrentUser, Float.MAX_VALUE) - contrast) >= 1e-10) {
+ mContrasts.put(mCurrentUser, contrast);
+ return true;
+ }
+ return false;
+ }
+
private static class ProjectionHolder implements IBinder.DeathRecipient {
private final String mPackageName;
private final @UiModeManager.ProjectionType int mProjectionType;