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 <nativehelper/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 <android-base/chrono_utils.h>
26 #include <utils/misc.h>
27 #include <utils/Log.h>
28 #include <map>
29 #include <stdio.h>
30 
31 namespace android {
32 
33 using Brightness = ::android::hardware::light::V2_0::Brightness;
34 using Flash      = ::android::hardware::light::V2_0::Flash;
35 using ILight     = ::android::hardware::light::V2_0::ILight;
36 using LightState = ::android::hardware::light::V2_0::LightState;
37 using Status     = ::android::hardware::light::V2_0::Status;
38 using Type       = ::android::hardware::light::V2_0::Type;
39 template<typename T>
40 using Return     = ::android::hardware::Return<T>;
41 
42 static bool sLightSupported = true;
43 
validate(jint light,jint flash,jint brightness)44 static bool validate(jint light, jint flash, jint brightness) {
45     bool valid = true;
46 
47     if (light < 0 || light >= static_cast<jint>(Type::COUNT)) {
48         ALOGE("Invalid light parameter %d.", light);
49         valid = false;
50     }
51 
52     if (flash != static_cast<jint>(Flash::NONE) &&
53         flash != static_cast<jint>(Flash::TIMED) &&
54         flash != static_cast<jint>(Flash::HARDWARE)) {
55         ALOGE("Invalid flash parameter %d.", flash);
56         valid = false;
57     }
58 
59     if (brightness != static_cast<jint>(Brightness::USER) &&
60         brightness != static_cast<jint>(Brightness::SENSOR) &&
61         brightness != static_cast<jint>(Brightness::LOW_PERSISTENCE)) {
62         ALOGE("Invalid brightness parameter %d.", brightness);
63         valid = false;
64     }
65 
66     if (brightness == static_cast<jint>(Brightness::LOW_PERSISTENCE) &&
67         light != static_cast<jint>(Type::BACKLIGHT)) {
68         ALOGE("Cannot set low-persistence mode for non-backlight device.");
69         valid = false;
70     }
71 
72     return valid;
73 }
74 
constructState(jint colorARGB,jint flashMode,jint onMS,jint offMS,jint brightnessMode)75 static LightState constructState(
76         jint colorARGB,
77         jint flashMode,
78         jint onMS,
79         jint offMS,
80         jint brightnessMode){
81     Flash flash = static_cast<Flash>(flashMode);
82     Brightness brightness = static_cast<Brightness>(brightnessMode);
83 
84     LightState state{};
85 
86     if (brightness == Brightness::LOW_PERSISTENCE) {
87         state.flashMode = Flash::NONE;
88     } else {
89         // Only set non-brightness settings when not in low-persistence mode
90         state.flashMode = flash;
91         state.flashOnMs = onMS;
92         state.flashOffMs = offMS;
93     }
94 
95     state.color = colorARGB;
96     state.brightnessMode = brightness;
97 
98     return state;
99 }
100 
processReturn(const Return<Status> & ret,Type type,const LightState & state)101 static void processReturn(
102         const Return<Status> &ret,
103         Type type,
104         const LightState &state) {
105     if (!ret.isOk()) {
106         ALOGE("Failed to issue set light command.");
107         return;
108     }
109 
110     switch (static_cast<Status>(ret)) {
111         case Status::SUCCESS:
112             break;
113         case Status::LIGHT_NOT_SUPPORTED:
114             ALOGE("Light requested not available on this device. %d", type);
115             break;
116         case Status::BRIGHTNESS_NOT_SUPPORTED:
117             ALOGE("Brightness parameter not supported on this device: %d",
118                 state.brightnessMode);
119             break;
120         case Status::UNKNOWN:
121         default:
122             ALOGE("Unknown error setting light.");
123     }
124 }
125 
setLight_native(JNIEnv *,jobject,jint light,jint colorARGB,jint flashMode,jint onMS,jint offMS,jint brightnessMode)126 static void setLight_native(
127         JNIEnv* /* env */,
128         jobject /* clazz */,
129         jint light,
130         jint colorARGB,
131         jint flashMode,
132         jint onMS,
133         jint offMS,
134         jint brightnessMode) {
135 
136     if (!sLightSupported) {
137         return;
138     }
139 
140     if (!validate(light, flashMode, brightnessMode)) {
141         return;
142     }
143 
144     Type type = static_cast<Type>(light);
145     LightState state = constructState(
146         colorARGB, flashMode, onMS, offMS, brightnessMode);
147 
148     {
149         android::base::Timer t;
150         sp<ILight> hal = ILight::getService();
151         if (hal == nullptr) {
152             sLightSupported = false;
153             return;
154         }
155         Return<Status> ret = hal->setLight(type, state);
156         processReturn(ret, type, state);
157         if (t.duration() > 50ms) ALOGD("Excessive delay setting light");
158     }
159 }
160 
161 static const JNINativeMethod method_table[] = {
162     { "setLight_native", "(IIIIII)V", (void*)setLight_native },
163 };
164 
register_android_server_LightsService(JNIEnv * env)165 int register_android_server_LightsService(JNIEnv *env) {
166     return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService",
167             method_table, NELEM(method_table));
168 }
169 
170 };
171