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

Commit 11c9a2b8 authored by Vaibhav Devmurari's avatar Vaibhav Devmurari
Browse files

Add UObserver on creation of keyboard backlight sysfs nodes

Test: test inputflinger_tests
Bug: 265057712
Change-Id: If142cdbfd2f92d1278d01d97fb8abcf3b80a0fc5
parent 2af97cb1
Loading
Loading
Loading
Loading
+44 −0
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UEventObserver;
import android.text.TextUtils;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
@@ -69,6 +71,8 @@ final class KeyboardBacklightController implements
    private static final int MAX_BRIGHTNESS = 255;
    private static final int NUM_BRIGHTNESS_CHANGE_STEPS = 10;

    private static final String UEVENT_KEYBOARD_BACKLIGHT_TAG = "kbd_backlight";

    @VisibleForTesting
    static final long USER_INACTIVITY_THRESHOLD_MILLIS = Duration.ofSeconds(30).toMillis();

@@ -120,6 +124,18 @@ final class KeyboardBacklightController implements
        Message msg = Message.obtain(mHandler, MSG_UPDATE_EXISTING_DEVICES,
                inputManager.getInputDeviceIds());
        mHandler.sendMessage(msg);

        // Observe UEvents for "kbd_backlight" sysfs nodes.
        // We want to observe creation of such LED nodes since they might be created after device
        // FD created and InputDevice creation logic doesn't initialize LED nodes which leads to
        // backlight not working.
        UEventObserver observer = new UEventObserver() {
            @Override
            public void onUEvent(UEvent event) {
                onKeyboardBacklightUEvent(event);
            }
        };
        observer.startObserving(UEVENT_KEYBOARD_BACKLIGHT_TAG);
    }

    @Override
@@ -386,6 +402,34 @@ final class KeyboardBacklightController implements
        }
    }

    @VisibleForTesting
    public void onKeyboardBacklightUEvent(UEventObserver.UEvent event) {
        if ("ADD".equalsIgnoreCase(event.get("ACTION")) && "LEDS".equalsIgnoreCase(
                event.get("SUBSYSTEM"))) {
            final String devPath = event.get("DEVPATH");
            if (isValidBacklightNodePath(devPath)) {
                mNative.sysfsNodeChanged("/sys" + devPath);
            }
        }
    }

    private static boolean isValidBacklightNodePath(String devPath) {
        if (TextUtils.isEmpty(devPath)) {
            return false;
        }
        int index = devPath.lastIndexOf('/');
        if (index < 0) {
            return false;
        }
        String backlightNode = devPath.substring(index + 1);
        devPath = devPath.substring(0, index);
        if (!devPath.endsWith("leds") || !backlightNode.contains("kbd_backlight")) {
            return false;
        }
        index = devPath.lastIndexOf('/');
        return index >= 0;
    }

    @Override
    public void dump(PrintWriter pw) {
        IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
+9 −0
Original line number Diff line number Diff line
@@ -237,6 +237,12 @@ interface NativeInputManagerService {
    /** Set whether showing a pointer icon for styluses is enabled. */
    void setStylusPointerIconEnabled(boolean enabled);

    /**
     * Report sysfs node changes. This may result in recreation of the corresponding InputDevice.
     * The recreated device may contain new associated peripheral devices like Light, Battery, etc.
     */
    void sysfsNodeChanged(String sysfsNodePath);

    /** The native implementation of InputManagerService methods. */
    class NativeImpl implements NativeInputManagerService {
        /** Pointer to native input manager service object, used by native code. */
@@ -484,5 +490,8 @@ interface NativeInputManagerService {

        @Override
        public native void setStylusPointerIconEnabled(boolean enabled);

        @Override
        public native void sysfsNodeChanged(String sysfsNodePath);
    }
}
+9 −0
Original line number Diff line number Diff line
@@ -2336,6 +2336,14 @@ static void nativeReloadDeviceAliases(JNIEnv* env, jobject nativeImplObj) {
            InputReaderConfiguration::CHANGE_DEVICE_ALIAS);
}

static void nativeSysfsNodeChanged(JNIEnv* env, jobject nativeImplObj, jstring path) {
    ScopedUtfChars sysfsNodePathChars(env, path);
    const std::string sysfsNodePath = sysfsNodePathChars.c_str();

    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
    im->getInputManager()->getReader().sysfsNodeChanged(sysfsNodePath);
}

static std::string dumpInputProperties() {
    std::string out = "Input properties:\n";
    const std::string strategy =
@@ -2651,6 +2659,7 @@ static const JNINativeMethod gInputManagerMethods[] = {
        {"getBatteryDevicePath", "(I)Ljava/lang/String;", (void*)nativeGetBatteryDevicePath},
        {"reloadKeyboardLayouts", "()V", (void*)nativeReloadKeyboardLayouts},
        {"reloadDeviceAliases", "()V", (void*)nativeReloadDeviceAliases},
        {"sysfsNodeChanged", "(Ljava/lang/String;)V", (void*)nativeSysfsNodeChanged},
        {"dump", "()Ljava/lang/String;", (void*)nativeDump},
        {"monitor", "()V", (void*)nativeMonitor},
        {"isInputDeviceEnabled", "(I)Z", (void*)nativeIsInputDeviceEnabled},
+64 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.hardware.input.IKeyboardBacklightListener
import android.hardware.input.IKeyboardBacklightState
import android.hardware.input.InputManager
import android.hardware.lights.Light
import android.os.UEventObserver
import android.os.test.TestLooper
import android.platform.test.annotations.Presubmit
import android.view.InputDevice
@@ -39,6 +40,7 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.eq
import org.mockito.Mockito.spy
@@ -95,6 +97,7 @@ class KeyboardBacklightControllerTests {
    private lateinit var testLooper: TestLooper
    private var lightColorMap: HashMap<Int, Int> = HashMap()
    private var lastBacklightState: KeyboardBacklightState? = null
    private var sysfsNodeChanges = 0

    @Before
    fun setup() {
@@ -121,6 +124,9 @@ class KeyboardBacklightControllerTests {
            lightColorMap.put(args[1] as Int, args[2] as Int)
        }
        lightColorMap.clear()
        `when`(native.sysfsNodeChanged(any())).then {
            sysfsNodeChanges++
        }
    }

    @After
@@ -393,6 +399,64 @@ class KeyboardBacklightControllerTests {
        )
    }

    @Test
    fun testKeyboardBacklightSysfsNodeAdded_AfterInputDeviceAdded() {
        var counter = sysfsNodeChanges
        keyboardBacklightController.onKeyboardBacklightUEvent(UEventObserver.UEvent(
            "ACTION=add\u0000SUBSYSTEM=leds\u0000DEVPATH=/xyz/leds/abc::no_backlight\u0000"
        ))
        assertEquals(
            "Should not reload sysfs node if UEvent path doesn't contain kbd_backlight",
            counter,
            sysfsNodeChanges
        )

        keyboardBacklightController.onKeyboardBacklightUEvent(UEventObserver.UEvent(
            "ACTION=add\u0000SUBSYSTEM=power\u0000DEVPATH=/xyz/leds/abc::kbd_backlight\u0000"
        ))
        assertEquals(
            "Should not reload sysfs node if UEvent doesn't belong to subsystem LED",
            counter,
            sysfsNodeChanges
        )

        keyboardBacklightController.onKeyboardBacklightUEvent(UEventObserver.UEvent(
            "ACTION=remove\u0000SUBSYSTEM=leds\u0000DEVPATH=/xyz/leds/abc::kbd_backlight\u0000"
        ))
        assertEquals(
            "Should not reload sysfs node if UEvent doesn't have ACTION(add)",
            counter,
            sysfsNodeChanges
        )

        keyboardBacklightController.onKeyboardBacklightUEvent(UEventObserver.UEvent(
            "ACTION=add\u0000SUBSYSTEM=leds\u0000DEVPATH=/xyz/pqr/abc::kbd_backlight\u0000"
        ))
        assertEquals(
            "Should not reload sysfs node if UEvent path doesn't belong to leds/ directory",
            counter,
            sysfsNodeChanges
        )

        keyboardBacklightController.onKeyboardBacklightUEvent(UEventObserver.UEvent(
            "ACTION=add\u0000SUBSYSTEM=leds\u0000DEVPATH=/xyz/leds/abc::kbd_backlight\u0000"
        ))
        assertEquals(
            "Should reload sysfs node if a valid Keyboard backlight LED UEvent occurs",
            ++counter,
            sysfsNodeChanges
        )

        keyboardBacklightController.onKeyboardBacklightUEvent(UEventObserver.UEvent(
            "ACTION=add\u0000SUBSYSTEM=leds\u0000DEVPATH=/xyz/leds/abc:kbd_backlight:red\u0000"
        ))
        assertEquals(
            "Should reload sysfs node if a valid Keyboard backlight LED UEvent occurs",
            ++counter,
            sysfsNodeChanges
        )
    }

    inner class KeyboardBacklightListener : IKeyboardBacklightListener.Stub() {
        override fun onBrightnessChanged(
            deviceId: Int,