1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "LightsService"
18
19#include "jni.h"
20#include "JNIHelp.h"
21#include "android_runtime/AndroidRuntime.h"
22
23#include <android/hardware/light/2.0/ILight.h>
24#include <android/hardware/light/2.0/types.h>
25#include <utils/misc.h>
26#include <utils/Log.h>
27#include <map>
28#include <stdio.h>
29
30namespace android {
31
32using Brightness = ::android::hardware::light::V2_0::Brightness;
33using Flash      = ::android::hardware::light::V2_0::Flash;
34using ILight     = ::android::hardware::light::V2_0::ILight;
35using LightState = ::android::hardware::light::V2_0::LightState;
36using Status     = ::android::hardware::light::V2_0::Status;
37using Type       = ::android::hardware::light::V2_0::Type;
38template<typename T>
39using Return     = ::android::hardware::Return<T>;
40
41class LightHal {
42private:
43    static sp<ILight> sLight;
44    static bool sLightInit;
45
46    LightHal() {}
47
48public:
49    static void disassociate() {
50        sLightInit = false;
51        sLight = nullptr;
52    }
53
54    static sp<ILight> associate() {
55        if ((sLight == nullptr && !sLightInit) ||
56                (sLight != nullptr && !sLight->ping().isOk())) {
57            // will return the hal if it exists the first time.
58            sLight = ILight::getService();
59            sLightInit = true;
60
61            if (sLight == nullptr) {
62                ALOGE("Unable to get ILight interface.");
63            }
64        }
65
66        return sLight;
67    }
68};
69
70sp<ILight> LightHal::sLight = nullptr;
71bool LightHal::sLightInit = false;
72
73static bool validate(jint light, jint flash, jint brightness) {
74    bool valid = true;
75
76    if (light < 0 || light >= static_cast<jint>(Type::COUNT)) {
77        ALOGE("Invalid light parameter %d.", light);
78        valid = false;
79    }
80
81    if (flash != static_cast<jint>(Flash::NONE) &&
82        flash != static_cast<jint>(Flash::TIMED) &&
83        flash != static_cast<jint>(Flash::HARDWARE)) {
84        ALOGE("Invalid flash parameter %d.", flash);
85        valid = false;
86    }
87
88    if (brightness != static_cast<jint>(Brightness::USER) &&
89        brightness != static_cast<jint>(Brightness::SENSOR) &&
90        brightness != static_cast<jint>(Brightness::LOW_PERSISTENCE)) {
91        ALOGE("Invalid brightness parameter %d.", brightness);
92        valid = false;
93    }
94
95    if (brightness == static_cast<jint>(Brightness::LOW_PERSISTENCE) &&
96        light != static_cast<jint>(Type::BACKLIGHT)) {
97        ALOGE("Cannot set low-persistence mode for non-backlight device.");
98        valid = false;
99    }
100
101    return valid;
102}
103
104static LightState constructState(
105        jint colorARGB,
106        jint flashMode,
107        jint onMS,
108        jint offMS,
109        jint brightnessMode){
110    Flash flash = static_cast<Flash>(flashMode);
111    Brightness brightness = static_cast<Brightness>(brightnessMode);
112
113    LightState state{};
114
115    if (brightness == Brightness::LOW_PERSISTENCE) {
116        state.flashMode = Flash::NONE;
117    } else {
118        // Only set non-brightness settings when not in low-persistence mode
119        state.flashMode = flash;
120        state.flashOnMs = onMS;
121        state.flashOffMs = offMS;
122    }
123
124    state.color = colorARGB;
125    state.brightnessMode = brightness;
126
127    return state;
128}
129
130static void processReturn(
131        const Return<Status> &ret,
132        Type type,
133        const LightState &state) {
134    if (!ret.isOk()) {
135        ALOGE("Failed to issue set light command.");
136        LightHal::disassociate();
137        return;
138    }
139
140    switch (static_cast<Status>(ret)) {
141        case Status::SUCCESS:
142            break;
143        case Status::LIGHT_NOT_SUPPORTED:
144            ALOGE("Light requested not available on this device. %d", type);
145            break;
146        case Status::BRIGHTNESS_NOT_SUPPORTED:
147            ALOGE("Brightness parameter not supported on this device: %d",
148                state.brightnessMode);
149            break;
150        case Status::UNKNOWN:
151        default:
152            ALOGE("Unknown error setting light.");
153    }
154}
155
156static void setLight_native(
157        JNIEnv* /* env */,
158        jobject /* clazz */,
159        jint light,
160        jint colorARGB,
161        jint flashMode,
162        jint onMS,
163        jint offMS,
164        jint brightnessMode) {
165
166    if (!validate(light, flashMode, brightnessMode)) {
167        return;
168    }
169
170    sp<ILight> hal = LightHal::associate();
171
172    if (hal == nullptr) {
173        return;
174    }
175
176    Type type = static_cast<Type>(light);
177    LightState state = constructState(
178        colorARGB, flashMode, onMS, offMS, brightnessMode);
179
180    {
181        ALOGD_IF_SLOW(50, "Excessive delay setting light");
182        Return<Status> ret = hal->setLight(type, state);
183        processReturn(ret, type, state);
184    }
185}
186
187static const JNINativeMethod method_table[] = {
188    { "setLight_native", "(IIIIII)V", (void*)setLight_native },
189};
190
191int register_android_server_LightsService(JNIEnv *env) {
192    return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService",
193            method_table, NELEM(method_table));
194}
195
196};
197