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

Commit 97ee7462 authored by dk1978's avatar dk1978
Browse files

FP3: Rework device Light HAL

We now support pulsing ("breathing") as well as flashing
effect for the notification LED at the top. Since the Android
framework does not differentiate between
pulsing and flashing LEDs we activate breathing for the
pair of (on,off) durations equal to (1000ms,1000ms). This corresponds
to the "Normal/Normal" setting in the UI Settings and is
the only mode used on the device until now. For other pulse duration
time combinations we now activate flashing. To test this, go to
"Settings/Apps & notifications/Notifications/Advanced/Notification light"
and try changing settings for "Default" or individual apps.

Note that the kernel driver code does not support breathing
or flashing with less than full brightness, hence
we cannot support all colors for these modes but
compromise based on the brightness components instead to at least
produce all 2**3 possible color combinations for pulsing or flashing.
Controlling the start or light flash phase for RGB components appears
to be a challenge, thus changing lights rapidly can occasionally
lead to odd effects such as LED alternatingly flashing red and green
rather than flashing yellow. Setting normal constant colors is
possible with any brightness between 0 and 255 for all three
components, thus allowing all color combinations.

While at it, also put a stop to the log spam
"Light requested not available on this device. 2" (Buttons)
by simply ignoring the request rather than returning an
error condition.

Change-Id: I218be98d78d4629c111a25cfc4f68ad18cc758cf
parent fe68c694
Loading
Loading
Loading
Loading
+46 −53
Original line number Diff line number Diff line
@@ -39,51 +39,6 @@
#define DELAY_OFF       "delay_off"
#define DELAY_ON        "delay_on"


static void set_breath(int redBrightness,int greenBrightness, int blueBrightness) {
    int red = open(RED_LED BREATH,O_WRONLY);
    int green = open(GREEN_LED BREATH,O_WRONLY);
    int blue = open(BLUE_LED BREATH,O_WRONLY);

    if(red == -1) {
        ALOGE("failed to open " RED_LED BREATH);
    }

    if(green == -1) {
        ALOGE("failed to open " GREEN_LED BREATH);
    }

    if(blue == -1) {
        ALOGE("failed to open " BLUE_LED BREATH);
    }

    int re,ge,be;
    if (redBrightness > 0)
        re = write(red,"1",1);
    else
        re = write(red,"0",1);

    if (greenBrightness > 0)
        ge = write(green,"1",1);
    else
        ge = write(green,"0",1);

    if (blueBrightness > 0)
        be = write(blue,"1",1);
    else
        be = write(blue,"0",1);

    if(re != 1)
        ALOGE("failed to write to " RED_LED BREATH " errorcode: %i",re);
    if(ge != 1)
        ALOGE("failed to write to " GREEN_LED BREATH " errorcode: %i",ge);
    if(be != 1)
        ALOGE("failed to write to " BLUE_LED BREATH " errorcode: %i",be);
    close(red);
    close(green);
    close(blue);
}

/*
 * Write value to path and close file.
 */
@@ -102,6 +57,39 @@ static void set(std::string path, int value) {
    set(path, std::to_string(value));
}

static void set_blink(uint32_t redBrightness, uint32_t greenBrightness, uint32_t blueBrightness, uint32_t flashOnMs, uint32_t flashOffMs) {
    /*  Special case for flashOnMs == flashOffMs == 1000: use breathing effect */
    if (flashOnMs == 1000 && flashOffMs == 1000) {
        set(RED_LED BREATH, redBrightness > 128 ? 1 : 0);
        set(GREEN_LED BREATH, greenBrightness > 128 ? 1 : 0);
        set(BLUE_LED BREATH, blueBrightness > 128 ? 1 : 0);
    } else {
        if (redBrightness > 128) {
            set(RED_LED DELAY_ON, flashOnMs);
            set(RED_LED DELAY_OFF, flashOffMs);
        }
        else {
            set(RED_LED BRIGHTNESS, 0);
        }

        if (greenBrightness > 128) {
            set(GREEN_LED DELAY_ON, flashOnMs);
            set(GREEN_LED DELAY_OFF, flashOffMs);
        }
        else {
            set(GREEN_LED BRIGHTNESS, 0);
        }

        if (blueBrightness > 128 ) {
            set(BLUE_LED DELAY_ON, flashOnMs);
            set(BLUE_LED DELAY_OFF, flashOffMs);
        }
        else {
            set(BLUE_LED BRIGHTNESS, 0);
        }
    }
}

static void handleBacklight(const LightState& state) {
    uint32_t brightness = state.color & 0xFF;
    set(LCD_LED BRIGHTNESS, brightness);
@@ -128,17 +116,21 @@ static void handleNotification(const LightState& state) {
        blueBrightness = (blueBrightness * brightness) / 0xFF;
    }

    /* Disable blinking. */
    set_breath(0,0,0);

    if (state.flashMode == Flash::TIMED) {
        /* Enable blinking. */
        set_breath(redBrightness, greenBrightness, blueBrightness);
    } else {
    if (state.flashMode == Flash::NONE) {
        set(RED_LED BRIGHTNESS, redBrightness);
        set(GREEN_LED BRIGHTNESS, greenBrightness);
        set(BLUE_LED BRIGHTNESS, blueBrightness);
    }
    else if (state.flashMode == Flash::TIMED) {
        /* Enable blinking and breathing.*/
        set_blink(redBrightness, greenBrightness, blueBrightness, state.flashOnMs, state.flashOffMs);
    }
}

/* Since higher level code seems to never query which lights
   are actually implemented and keeps trying to set state for backend
   'BUTTONS', drop these requests silently to avoid log spam. */
static void handleIgnore(const LightState&) {
}

static inline bool isLit(const LightState& state) {
@@ -150,6 +142,7 @@ static std::vector<LightBackend> backends = {
    { Type::ATTENTION, handleNotification },
    { Type::NOTIFICATIONS, handleNotification },
    { Type::BATTERY, handleNotification },
    { Type::BUTTONS, handleIgnore },
    { Type::BACKLIGHT, handleBacklight }
};