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

Commit 3becba6b authored by Vaibhav Devmurari's avatar Vaibhav Devmurari
Browse files

Add support for custom keyboard backlight levels via IDC file

Test: atest KeyboardBacklightControllerTests
Bug: 280797494
Change-Id: Ib9e919ad280d8f8f7adf3491fab2f69616af1762
parent e043e8b7
Loading
Loading
Loading
Loading
+29 −1
Original line number Diff line number Diff line
@@ -110,6 +110,8 @@ public final class Light implements Parcelable {
    private final int mOrdinal;
    private final int mType;
    private final int mCapabilities;
    @Nullable
    private final int[] mPreferredBrightnessLevels;

    /**
     * Creates a new light with the given data.
@@ -117,7 +119,7 @@ public final class Light implements Parcelable {
     * @hide
     */
    public Light(int id, int ordinal, int type) {
        this(id, "Light", ordinal, type, 0);
        this(id, "Light", ordinal, type, 0, null);
    }

    /**
@@ -126,11 +128,22 @@ public final class Light implements Parcelable {
     * @hide
     */
    public Light(int id, String name, int ordinal, int type, int capabilities) {
        this(id, name, ordinal, type, capabilities, null);
    }

    /**
     * Creates a new light with the given data.
     *
     * @hide
     */
    public Light(int id, String name, int ordinal, int type, int capabilities,
            @Nullable int[] preferredBrightnessLevels) {
        mId = id;
        mName = name;
        mOrdinal = ordinal;
        mType = type;
        mCapabilities = capabilities;
        mPreferredBrightnessLevels = preferredBrightnessLevels;
    }

    private Light(@NonNull Parcel in) {
@@ -139,6 +152,7 @@ public final class Light implements Parcelable {
        mOrdinal = in.readInt();
        mType = in.readInt();
        mCapabilities = in.readInt();
        mPreferredBrightnessLevels = in.createIntArray();
    }

    /** Implement the Parcelable interface */
@@ -149,6 +163,7 @@ public final class Light implements Parcelable {
        dest.writeInt(mOrdinal);
        dest.writeInt(mType);
        dest.writeInt(mCapabilities);
        dest.writeIntArray(mPreferredBrightnessLevels);
    }

    /** Implement the Parcelable interface */
@@ -252,4 +267,17 @@ public final class Light implements Parcelable {
        return (mCapabilities & LIGHT_CAPABILITY_COLOR_RGB) == LIGHT_CAPABILITY_COLOR_RGB;
    }

    /**
     * Returns preferred brightness levels for the light which will be used when user
     * increase/decrease brightness levels for the light (currently only used for Keyboard
     * backlight control using backlight up/down keys).
     *
     * The values in the preferred brightness level array are in the range [0, 255].
     *
     * @hide
     */
    @Nullable
    public int[] getPreferredBrightnessLevels() {
        return mPreferredBrightnessLevels;
    }
}
+17 −0
Original line number Diff line number Diff line
@@ -38,8 +38,15 @@ public final class InputFeatureFlagProvider {
    private static final boolean KEYBOARD_BACKLIGHT_ANIMATION_ENABLED =
            InputProperties.enable_keyboard_backlight_animation().orElse(false);

    // To disable Custom keyboard backlight levels support via IDC files run:
    // adb shell setprop persist.input.keyboard_backlight_custom_levels.enabled false (requires
    // restart)
    private static final boolean KEYBOARD_BACKLIGHT_CUSTOM_LEVELS_ENABLED =
            InputProperties.enable_keyboard_backlight_custom_levels().orElse(true);

    private static Optional<Boolean> sKeyboardBacklightControlOverride = Optional.empty();
    private static Optional<Boolean> sKeyboardBacklightAnimationOverride = Optional.empty();
    private static Optional<Boolean> sKeyboardBacklightCustomLevelsOverride = Optional.empty();

    public static boolean isKeyboardBacklightControlEnabled() {
        return sKeyboardBacklightControlOverride.orElse(KEYBOARD_BACKLIGHT_CONTROL_ENABLED);
@@ -49,6 +56,11 @@ public final class InputFeatureFlagProvider {
        return sKeyboardBacklightAnimationOverride.orElse(KEYBOARD_BACKLIGHT_ANIMATION_ENABLED);
    }

    public static boolean isKeyboardBacklightCustomLevelsEnabled() {
        return sKeyboardBacklightCustomLevelsOverride.orElse(
                KEYBOARD_BACKLIGHT_CUSTOM_LEVELS_ENABLED);
    }

    public static void setKeyboardBacklightControlEnabled(boolean enabled) {
        sKeyboardBacklightControlOverride = Optional.of(enabled);
    }
@@ -57,11 +69,16 @@ public final class InputFeatureFlagProvider {
        sKeyboardBacklightAnimationOverride = Optional.of(enabled);
    }

    public static void setKeyboardBacklightCustomLevelsEnabled(boolean enabled) {
        sKeyboardBacklightCustomLevelsOverride = Optional.of(enabled);
    }

    /**
     * Clears all input feature flag overrides.
     */
    public static void clearOverrides() {
        sKeyboardBacklightControlOverride = Optional.empty();
        sKeyboardBacklightAnimationOverride = Optional.empty();
        sKeyboardBacklightCustomLevelsOverride = Optional.empty();
    }
}
+54 −18
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import java.time.Duration;
import java.util.Arrays;
import java.util.Objects;
import java.util.OptionalInt;
import java.util.TreeSet;

/**
 * A thread-safe component of {@link InputManagerService} responsible for managing the keyboard
@@ -70,7 +71,9 @@ final class KeyboardBacklightController implements
    private static final int MSG_NOTIFY_USER_INACTIVITY = 5;
    private static final int MSG_INTERACTIVE_STATE_CHANGED = 6;
    private static final int MAX_BRIGHTNESS = 255;
    private static final int NUM_BRIGHTNESS_CHANGE_STEPS = 10;
    private static final int DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS = 10;
    @VisibleForTesting
    static final int MAX_BRIGHTNESS_CHANGE_STEPS = 10;
    private static final long TRANSITION_ANIMATION_DURATION_MILLIS =
            Duration.ofSeconds(1).toMillis();

@@ -80,7 +83,8 @@ final class KeyboardBacklightController implements
    static final long USER_INACTIVITY_THRESHOLD_MILLIS = Duration.ofSeconds(30).toMillis();

    @VisibleForTesting
    static final int[] BRIGHTNESS_VALUE_FOR_LEVEL = new int[NUM_BRIGHTNESS_CHANGE_STEPS + 1];
    static final int[] DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL =
            new int[DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS + 1];

    private final Context mContext;
    private final NativeInputManagerService mNative;
@@ -104,10 +108,10 @@ final class KeyboardBacklightController implements
    static {
        // Fixed brightness levels to avoid issues when converting back and forth from the
        // device brightness range to [0-255]
        // Levels are: 0, 25, 51, ..., 255
        for (int i = 0; i <= NUM_BRIGHTNESS_CHANGE_STEPS; i++) {
            BRIGHTNESS_VALUE_FOR_LEVEL[i] = (int) Math.floor(
                    ((float) i * MAX_BRIGHTNESS) / NUM_BRIGHTNESS_CHANGE_STEPS);
        // Levels are: 0, 51, ..., 255
        for (int i = 0; i <= DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS; i++) {
            DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[i] = (int) Math.floor(
                    ((float) i * MAX_BRIGHTNESS) / DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS);
        }
    }

@@ -184,7 +188,8 @@ final class KeyboardBacklightController implements
        final int currBrightnessLevel = state.mBrightnessLevel;
        final int newBrightnessLevel;
        if (direction == Direction.DIRECTION_UP) {
            newBrightnessLevel = Math.min(currBrightnessLevel + 1, NUM_BRIGHTNESS_CHANGE_STEPS);
            newBrightnessLevel = Math.min(currBrightnessLevel + 1,
                    state.getNumBrightnessChangeSteps());
        } else {
            newBrightnessLevel = Math.max(currBrightnessLevel - 1, 0);
        }
@@ -194,7 +199,7 @@ final class KeyboardBacklightController implements
            try {
                mDataStore.setKeyboardBacklightBrightness(inputDevice.getDescriptor(),
                        keyboardBacklight.getId(),
                        BRIGHTNESS_VALUE_FOR_LEVEL[newBrightnessLevel]);
                        state.mBrightnessValueForLevel[newBrightnessLevel]);
            } finally {
                mDataStore.saveIfNeeded();
            }
@@ -202,6 +207,7 @@ final class KeyboardBacklightController implements
    }

    private void restoreBacklightBrightness(InputDevice inputDevice, Light keyboardBacklight) {
        KeyboardBacklightState state = mKeyboardBacklights.get(inputDevice.getId());
        OptionalInt brightness;
        synchronized (mDataStore) {
            brightness = mDataStore.getKeyboardBacklightBrightness(
@@ -209,9 +215,9 @@ final class KeyboardBacklightController implements
        }
        if (brightness.isPresent()) {
            int brightnessValue = Math.max(0, Math.min(MAX_BRIGHTNESS, brightness.getAsInt()));
            int index = Arrays.binarySearch(BRIGHTNESS_VALUE_FOR_LEVEL, brightnessValue);
            int index = Arrays.binarySearch(state.mBrightnessValueForLevel, brightnessValue);
            if (index < 0) {
                index = Math.min(NUM_BRIGHTNESS_CHANGE_STEPS, -(index + 1));
                index = Math.min(state.getNumBrightnessChangeSteps(), -(index + 1));
            }
            updateBacklightState(inputDevice.getId(), index, false /* isTriggeredByKeyPress */);
            if (DEBUG) {
@@ -386,7 +392,7 @@ final class KeyboardBacklightController implements
            for (int i = 0; i < mKeyboardBacklightListenerRecords.size(); i++) {
                IKeyboardBacklightState callbackState = new IKeyboardBacklightState();
                callbackState.brightnessLevel = brightnessLevel;
                callbackState.maxBrightnessLevel = NUM_BRIGHTNESS_CHANGE_STEPS;
                callbackState.maxBrightnessLevel = state.getNumBrightnessChangeSteps();
                mKeyboardBacklightListenerRecords.valueAt(i).notifyKeyboardBacklightChanged(
                        deviceId, callbackState, isTriggeredByKeyPress);
            }
@@ -443,10 +449,6 @@ final class KeyboardBacklightController implements
        ipw.decreaseIndent();
    }

    private static boolean isAnimationEnabled() {
        return InputFeatureFlagProvider.isKeyboardBacklightAnimationEnabled();
    }

    // A record of a registered Keyboard backlight listener from one process.
    private class KeyboardBacklightListenerRecord implements IBinder.DeathRecipient {
        public final int mPid;
@@ -482,18 +484,52 @@ final class KeyboardBacklightController implements
        private final Light mLight;
        private int mBrightnessLevel;
        private ValueAnimator mAnimator;
        private final int[] mBrightnessValueForLevel;

        KeyboardBacklightState(int deviceId, Light light) {
            mDeviceId = deviceId;
            mLight = light;
            mBrightnessValueForLevel = setupBrightnessLevels();
        }

        private int[] setupBrightnessLevels() {
            if (!InputFeatureFlagProvider.isKeyboardBacklightCustomLevelsEnabled()) {
                return DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL;
            }
            int[] customLevels = mLight.getPreferredBrightnessLevels();
            if (customLevels == null || customLevels.length == 0) {
                return DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL;
            }
            TreeSet<Integer> brightnessLevels = new TreeSet<>();
            brightnessLevels.add(0);
            for (int level : customLevels) {
                if (level > 0 && level < MAX_BRIGHTNESS) {
                    brightnessLevels.add(level);
                }
            }
            brightnessLevels.add(MAX_BRIGHTNESS);
            int brightnessChangeSteps = brightnessLevels.size() - 1;
            if (brightnessChangeSteps > MAX_BRIGHTNESS_CHANGE_STEPS) {
                return DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL;
            }
            int[] result = new int[brightnessLevels.size()];
            int index = 0;
            for (int val : brightnessLevels) {
                result[index++] = val;
            }
            return result;
        }

        private int getNumBrightnessChangeSteps() {
            return mBrightnessValueForLevel.length - 1;
        }

        private void onBacklightStateChanged() {
            setBacklightValue(mIsBacklightOn ? BRIGHTNESS_VALUE_FOR_LEVEL[mBrightnessLevel] : 0);
            setBacklightValue(mIsBacklightOn ? mBrightnessValueForLevel[mBrightnessLevel] : 0);
        }
        private void setBrightnessLevel(int brightnessLevel) {
            if (mIsBacklightOn) {
                setBacklightValue(BRIGHTNESS_VALUE_FOR_LEVEL[brightnessLevel]);
                setBacklightValue(mBrightnessValueForLevel[brightnessLevel]);
            }
            mBrightnessLevel = brightnessLevel;
        }
@@ -509,7 +545,7 @@ final class KeyboardBacklightController implements
            if (fromValue == toValue) {
                return;
            }
            if (isAnimationEnabled()) {
            if (InputFeatureFlagProvider.isKeyboardBacklightAnimationEnabled()) {
                startAnimation(fromValue, toValue);
            } else {
                mNative.setLightColor(mDeviceId, mLight.getId(), Color.argb(toValue, 0, 0, 0));
+14 −2
Original line number Diff line number Diff line
@@ -2214,13 +2214,25 @@ static jobject nativeGetLights(JNIEnv* env, jobject nativeImplObj, jint deviceId
            jCapability |= env->GetStaticIntField(gLightClassInfo.clazz,
                                                  gLightClassInfo.lightCapabilityColorRgb);
        }

        ScopedLocalRef<jintArray> jPreferredBrightnessLevels{env};
        if (!lightInfo.preferredBrightnessLevels.empty()) {
            std::vector<int32_t> vec;
            for (auto it : lightInfo.preferredBrightnessLevels) {
              vec.push_back(ftl::to_underlying(it));
            }
            jPreferredBrightnessLevels.reset(env->NewIntArray(vec.size()));
            env->SetIntArrayRegion(jPreferredBrightnessLevels.get(), 0, vec.size(), vec.data());
        }

        ScopedLocalRef<jobject> lightObj(env,
                                         env->NewObject(gLightClassInfo.clazz,
                                                        gLightClassInfo.constructor,
                                                        static_cast<jint>(lightInfo.id),
                                                        env->NewStringUTF(lightInfo.name.c_str()),
                                                        static_cast<jint>(lightInfo.ordinal),
                                                        jTypeId, jCapability));
                                                        jTypeId, jCapability,
                                                        jPreferredBrightnessLevels.get()));
        // Add light object to list
        env->CallBooleanMethod(jLights, gArrayListClassInfo.add, lightObj.get());
    }
@@ -2846,7 +2858,7 @@ int register_android_server_InputManager(JNIEnv* env) {
    FIND_CLASS(gLightClassInfo.clazz, "android/hardware/lights/Light");
    gLightClassInfo.clazz = jclass(env->NewGlobalRef(gLightClassInfo.clazz));
    GET_METHOD_ID(gLightClassInfo.constructor, gLightClassInfo.clazz, "<init>",
                  "(ILjava/lang/String;III)V");
                  "(ILjava/lang/String;III[I)V");

    gLightClassInfo.clazz = jclass(env->NewGlobalRef(gLightClassInfo.clazz));
    gLightClassInfo.lightTypeInput =
+165 −87

File changed.

Preview size limit exceeded, changes collapsed.