Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 485fa630 authored by Aurélien Pomini's avatar Aurélien Pomini Committed by Android (Google) Code Review
Browse files

Merge "Add API to get/listen to the color contrast setting"

parents 9adfd2be bd1d59c5
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -52785,12 +52785,14 @@ 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();
@@ -52802,6 +52804,7 @@ 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
@@ -52824,6 +52827,10 @@ 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);
+117 −2
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ 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;
@@ -75,6 +76,7 @@ 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;

/**
@@ -137,6 +139,21 @@ public final class AccessibilityManager {
    /** @hide */
    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.
@@ -246,6 +263,8 @@ public final class AccessibilityManager {
    @UnsupportedAppUsage(trackingBug = 123768939L)
    boolean mIsHighTextContrastEnabled;

    private float mUiContrast;

    boolean mIsAudioDescriptionByDefaultRequested;

    // accessibility tracing state
@@ -270,6 +289,9 @@ 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<>();

@@ -357,6 +379,21 @@ public final class AccessibilityManager {
        void onHighTextContrastStateChanged(boolean enabled);
    }

    /**
     * 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,
@@ -471,6 +508,16 @@ 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();
        }
    };

    /**
@@ -641,7 +688,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 you application is
     * <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>
     *
@@ -660,6 +707,24 @@ 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}.
     *
@@ -1239,6 +1304,35 @@ 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.
@@ -2004,6 +2098,7 @@ 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);
@@ -2081,6 +2176,22 @@ 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.
     */
@@ -2171,6 +2282,7 @@ 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) {
@@ -2182,6 +2294,9 @@ public final class AccessibilityManager {
                        setStateLocked(state);
                    }
                } break;
                case MSG_NOTIFY_CONTRAST_CHANGED: {
                    notifyUiContrastChanged();
                }
            }
            return true;
        }
+2 −0
Original line number Diff line number Diff line
@@ -118,4 +118,6 @@ interface IAccessibilityManager {

    // Used by UiAutomation for tests on the InputFilter
    void injectInputEventToInputFilter(in InputEvent event);

    float getUiContrast();
}
+2 −0
Original line number Diff line number Diff line
@@ -31,4 +31,6 @@ oneway interface IAccessibilityManagerClient {
    void setRelevantEventTypes(int eventTypes);

    void setFocusAppearance(int strokeWidth, int color);

    void setUiContrast(float contrast);
}
+51 −0
Original line number Diff line number Diff line
@@ -26,8 +26,11 @@ 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.ShortcutType;

import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
@@ -1902,6 +1905,16 @@ 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.
@@ -2568,6 +2581,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        somethingChanged |= readMagnificationModeForDefaultDisplayLocked(userState);
        somethingChanged |= readMagnificationCapabilitiesLocked(userState);
        somethingChanged |= readMagnificationFollowTypingLocked(userState);
        somethingChanged |= readUiContrastLocked(userState);
        return somethingChanged;
    }

@@ -3709,6 +3723,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        return mProxyManager.unregisterProxy(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 void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
        if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
@@ -4156,6 +4183,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        private final Uri mMagnificationFollowTypingUri = Settings.Secure.getUriFor(
                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED);

        private final Uri mUiContrastUri = Settings.Secure.getUriFor(
                CONTRAST_LEVEL);

        public AccessibilityContentObserver(Handler handler) {
            super(handler);
        }
@@ -4196,6 +4226,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                    mMagnificationCapabilityUri, false, this, UserHandle.USER_ALL);
            contentResolver.registerContentObserver(
                    mMagnificationFollowTypingUri, false, this, UserHandle.USER_ALL);
            contentResolver.registerContentObserver(
                    mUiContrastUri, false, this, UserHandle.USER_ALL);
        }

        @Override
@@ -4265,6 +4297,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                    }
                } else if (mMagnificationFollowTypingUri.equals(uri)) {
                    readMagnificationFollowTypingLocked(userState);
                } else if (mUiContrastUri.equals(uri)) {
                    if (readUiContrastLocked(userState)) {
                        updateUiContrastLocked(userState);
                    }
                }
            }
        }
@@ -4554,7 +4590,22 @@ 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() {
Loading