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

Commit f000fb68 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "feat(force invert): add ability to force-enable or disable force invert...

Merge "feat(force invert): add ability to force-enable or disable force invert per-package" into main
parents a831b323 946ef041
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -231,4 +231,11 @@ interface IUiModeManager {
     * @hide
     */
    int getForceInvertState(int userId);

    /**
     * Returns the force invert override state for the given package.
     *
     * @hide
     */
    int getForceInvertOverrideState(int userId, String packageName);
}
+1 −0
Original line number Diff line number Diff line
@@ -25,4 +25,5 @@ package android.app;
oneway interface IUiModeManagerCallback {
  void notifyContrastChanged(float contrast);
  void notifyForceInvertStateChanged(int forceInvertState);
  void notifyForceInvertOverrideStateChanged();
}
+103 −20
Original line number Diff line number Diff line
@@ -54,7 +54,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
@@ -424,6 +423,41 @@ public class UiModeManager {
     */
    public static final int FORCE_INVERT_TYPE_LIGHT = 2;

    /** @hide */
    @IntDef(prefix = {"FORCE_INVERT_PACKAGE_"}, value = {
            FORCE_INVERT_PACKAGE_ALLOWED,
            FORCE_INVERT_PACKAGE_ALWAYS_ENABLE,
            FORCE_INVERT_PACKAGE_ALWAYS_DISABLE,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ForceInvertPackageOverrideState {}

    /**
     * Constant for {@link #getForceInvertOverrideState()}: Force invert is allowed
     * for the package, and will be applied if the global setting is on.
     *
     * @hide
     */
    public static final int FORCE_INVERT_PACKAGE_ALLOWED = 0;

    /**
     * Constant for {@link #getForceInvertOverrideState()}: Force invert is always
     * enabled for the package, regardless of other overrides or criteria (as long as the {@link
     * #getForceInvertState()} global setting is on.
     *
     * @hide
     */
    public static final int FORCE_INVERT_PACKAGE_ALWAYS_ENABLE = 1;

    /**
     * Constant for {@link #getForceInvertOverrideState()}: Force invert is always
     * disabled for the package, regardless of other overrides or criteria (as long as the {@link
     * #getForceInvertState()} global setting is on.
     *
     * @hide
     */
    public static final int FORCE_INVERT_PACKAGE_ALWAYS_DISABLE = 2;

    private static Globals sGlobals;

    /**
@@ -492,11 +526,17 @@ public class UiModeManager {
        }

        @Override
        public void notifyForceInvertStateChanged(@ForceInvertType int forceInvertState) {
        public void notifyForceInvertStateChanged(@ForceInvertType int forceInvertState)
                throws RemoteException {
            notifyForceInvertStateChanged(forceInvertState, /* forceUpdate= */ false);
        }

        private void notifyForceInvertStateChanged(@ForceInvertType int forceInvertState,
                boolean forceUpdate) {
            final Map<ForceInvertStateChangeListener, Executor> listeners = new ArrayMap<>();
            synchronized (mGlobalsLock) {
                // if value changed in the settings, update the cached value and notify listeners
                if (mForceInvertState == forceInvertState) {
                if (mForceInvertState == forceInvertState && !forceUpdate) {
                    return;
                }

@@ -543,6 +583,18 @@ public class UiModeManager {
            }
        }

        @Override
        public void notifyForceInvertOverrideStateChanged() throws RemoteException {
            final int forceInvertState;
            synchronized (sGlobals.mGlobalsLock) {
                forceInvertState = mForceInvertState;
            }

            // We just re-use the main state listener. End clients don't need the granularity of
            // listening to the blocklist changes separately.
            notifyForceInvertStateChanged(forceInvertState, /* forceUpdate= */ true);
        }

        // ============= End legacy values and methods ============= //

        /**
@@ -657,6 +709,18 @@ public class UiModeManager {
                }
            }
        }

        @ForceInvertPackageOverrideState
        private int getForceInvertOverrideState(int userId, String packageName) {
            synchronized (mGlobalsLock) {
                // This is such an infrequent operation, we don't worry about caching.
                try {
                    return mService.getForceInvertOverrideState(userId, packageName);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
        }
    }

    /** Global class storing all listeners and cached values for a specific user id. */
@@ -698,6 +762,8 @@ public class UiModeManager {
                    return;
                }
                mContrast = contrast;

                // TODO(b/438028125): why doesn't this clear calling identity like the others?
                mContrastChangeListeners.forEach((listener, executor) ->
                        executor.execute(() -> listener.onContrastChanged(contrast)));
            }
@@ -706,10 +772,16 @@ public class UiModeManager {
        @Override
        public void notifyForceInvertStateChanged(@ForceInvertType int forceInvertState)
                throws RemoteException {
            notifyForceInvertStateChanged(forceInvertState, /* forceUpdate= */ false);
        }

        private void notifyForceInvertStateChanged(
                @ForceInvertType int forceInvertState, boolean forceUpdate)
                throws RemoteException {
            final Map<ForceInvertStateChangeListener, Executor> listeners = new ArrayMap<>();
            synchronized (sGlobals.mGlobalsLock) {
                // if value changed in the settings, update the cached value and notify listeners
                if (mForceInvertState == forceInvertState) {
                if (mForceInvertState == forceInvertState && !forceUpdate) {
                    return;
                }

@@ -726,6 +798,18 @@ public class UiModeManager {
                }
            });
        }

        @Override
        public void notifyForceInvertOverrideStateChanged() throws RemoteException {
            final int forceInvertState;
            synchronized (sGlobals.mGlobalsLock) {
                forceInvertState = mForceInvertState;
            }

            // We just re-use the main state listener. End clients don't need the granularity of
            // listening to the blocklist changes separately.
            notifyForceInvertStateChanged(forceInvertState, /* forceUpdate= */ true);
        }
    }

    /**
@@ -1752,22 +1836,6 @@ public class UiModeManager {
        return sGlobals.getForceInvertState();
    }

    /**
     * Returns {@code true} if the provided context allows applying force invert, otherwise
     * {@code false}.
     *
     * @hide
     */
    public static boolean isForceInvertAllowed(Context context) {
        final String packageName = context.getPackageName();
        final String[] packageBlocklist = context.getResources().getStringArray(
                com.android.internal.R.array.config_forceInvertPackageBlocklist);
        if (packageName != null && Arrays.asList(packageBlocklist).contains(packageName)) {
            return false;
        }
        return true;
    }

    /**
     * Registers a {@link ForceInvertStateChangeListener} for the user.
     *
@@ -1806,6 +1874,21 @@ public class UiModeManager {
        sGlobals.removeForceInvertStateChangeListener(listener);
    }

    /**
     * Returns the force invert override state for the current package.
     *
     * @hide
     */
    @ForceInvertPackageOverrideState
    public int getForceInvertOverrideState() {
        if (mContext == null) {
            // This shouldn't really happen in practice because ViewRootImpl uses the
            // proper constructor that fills out the context.
            return FORCE_INVERT_PACKAGE_ALLOWED;
        }
        return sGlobals.getForceInvertOverrideState(getUserId(), mContext.getOpPackageName());
    }

    /**
     * Return the context user id. If this class was built with the UnsupportedAppUsage constructor
     * and the context is null, return the user id of this process instead.
+23 −0
Original line number Diff line number Diff line
@@ -6589,6 +6589,27 @@ public final class Settings {
        @Readable
        public static final String EGG_MODE = "egg_mode";
        /**
         * Comma-separated string of package names will have force invert applied no matter what,
         * overriding any device-level config blocklists or other criteria, for debugging.
         *
         * Note: HWUI may still determine that the app already appears to be dark theme and may not
         * obey this setting.
         *
         * @hide
         */
        public static final String ACCESSIBILITY_FORCE_INVERT_COLOR_OVERRIDE_PACKAGES_TO_ENABLE =
                "accessibility_force_invert_color_override_packages_to_enable";
        /**
         * Comma-separated string of package names will *never* have force invert applied,
         * overriding any device-level config blocklists or other criteria, for debugging.
         *
         * @hide
         */
        public static final String ACCESSIBILITY_FORCE_INVERT_COLOR_OVERRIDE_PACKAGES_TO_DISABLE =
                "accessibility_force_invert_color_override_packages_to_disable";
        /**
         * Setting to determine whether or not to show the battery percentage in the status bar.
         *    0 - Don't show percentage
@@ -6770,6 +6791,8 @@ public final class Settings {
            PRIVATE_SETTINGS.add(WIFI_USE_STATIC_IP);
            PRIVATE_SETTINGS.add(END_BUTTON_BEHAVIOR);
            PRIVATE_SETTINGS.add(ADVANCED_SETTINGS);
            PRIVATE_SETTINGS.add(ACCESSIBILITY_FORCE_INVERT_COLOR_OVERRIDE_PACKAGES_TO_DISABLE);
            PRIVATE_SETTINGS.add(ACCESSIBILITY_FORCE_INVERT_COLOR_OVERRIDE_PACKAGES_TO_ENABLE);
            PRIVATE_SETTINGS.add(WEAR_ACCESSIBILITY_GESTURE_ENABLED);
            PRIVATE_SETTINGS.add(WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE);
            PRIVATE_SETTINGS.add(WEAR_TTS_PREWARM_ENABLED);
+25 −18
Original line number Diff line number Diff line
@@ -2068,19 +2068,15 @@ public final class ViewRootImpl implements ViewParent,
                }
            }
            if (shouldApplyForceInvertDark()) {
                // Do not apply force invert dark theme to an app that already declares itself as
            // Don't apply force invert dark theme to an app that already declares itself as
            // supporting dark theme (isLightTheme=false). This gives the developer a way to
            // opt out of allowing this behavior, while also guaranteeing that apps with a
            // properly configured dark theme are unaffected by force invert dark theme. For
            // self-declared light theme apps HWUI then performs its own "color area"
            // calculation to determine if the app actually renders with light colors.
                if (!isInputWindow() && a.getBoolean(R.styleable.Theme_isLightTheme, false)) {
                    return ForceDarkType.FORCE_INVERT_COLOR_DARK;
                }
            }
            return ForceDarkType.NONE;
            boolean shouldForceInvertDark = !isInputWindow()
                    && a.getBoolean(R.styleable.Theme_isLightTheme, false);
            return determineForceInvertDarkOverride(shouldForceInvertDark);
        } finally {
            a.recycle();
        }
@@ -2090,16 +2086,27 @@ public final class ViewRootImpl implements ViewParent,
        return mOrigWindowType == TYPE_INPUT_METHOD || mOrigWindowType == TYPE_INPUT_METHOD_DIALOG;
    }
    private boolean shouldApplyForceInvertDark() {
    private @ForceDarkType.ForceDarkTypeDef int determineForceInvertDarkOverride(
            boolean shouldForceInvertDark) {
        if (!forceInvertColor()) {
            return false;
            return ForceDarkType.NONE;
        }
        final UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
        if (uiModeManager == null) {
            return false;
            return ForceDarkType.NONE;
        }
        return uiModeManager.getForceInvertState() == UiModeManager.FORCE_INVERT_TYPE_DARK
                && UiModeManager.isForceInvertAllowed(mContext);
        if (uiModeManager.getForceInvertState() != UiModeManager.FORCE_INVERT_TYPE_DARK) {
            return ForceDarkType.NONE;
        }
        var overrideState = uiModeManager.getForceInvertOverrideState();
        return switch (overrideState) {
            case UiModeManager.FORCE_INVERT_PACKAGE_ALLOWED -> shouldForceInvertDark
                    ? ForceDarkType.FORCE_INVERT_COLOR_DARK : ForceDarkType.NONE;
            case UiModeManager.FORCE_INVERT_PACKAGE_ALWAYS_DISABLE -> ForceDarkType.NONE;
            case UiModeManager.FORCE_INVERT_PACKAGE_ALWAYS_ENABLE ->
                    ForceDarkType.FORCE_INVERT_COLOR_DARK;
            default -> throw new IllegalStateException("Invalid override state");
        };
    }
    private void updateForceDarkMode() {
Loading