• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 #include <locale>
18 #include <regex>
19 #include <sstream>
20 #include <string>
21 
22 #include <android/sysprop/InputProperties.sysprop.h>
23 #include <ftl/enum.h>
24 
25 #include "../Macros.h"
26 #include "PeripheralController.h"
27 
28 namespace android {
29 
getAlpha(int32_t color)30 static inline int32_t getAlpha(int32_t color) {
31     return (color >> 24) & 0xff;
32 }
33 
getRed(int32_t color)34 static inline int32_t getRed(int32_t color) {
35     return (color >> 16) & 0xff;
36 }
37 
getGreen(int32_t color)38 static inline int32_t getGreen(int32_t color) {
39     return (color >> 8) & 0xff;
40 }
41 
getBlue(int32_t color)42 static inline int32_t getBlue(int32_t color) {
43     return color & 0xff;
44 }
45 
toArgb(int32_t brightness,int32_t red,int32_t green,int32_t blue)46 static inline int32_t toArgb(int32_t brightness, int32_t red, int32_t green, int32_t blue) {
47     return (brightness & 0xff) << 24 | (red & 0xff) << 16 | (green & 0xff) << 8 | (blue & 0xff);
48 }
49 
isKeyboardBacklightCustomLevelsEnabled()50 static inline bool isKeyboardBacklightCustomLevelsEnabled() {
51     return sysprop::InputProperties::enable_keyboard_backlight_custom_levels().value_or(true);
52 }
53 
54 /**
55  * Input controller owned by InputReader device, implements the native API for querying input
56  * lights, getting and setting the lights brightness and color, by interacting with EventHub
57  * devices.
58  */
PeripheralController(InputDeviceContext & deviceContext)59 PeripheralController::PeripheralController(InputDeviceContext& deviceContext)
60       : mDeviceContext(deviceContext) {
61     configureBattries();
62     configureLights();
63 }
64 
~PeripheralController()65 PeripheralController::~PeripheralController() {}
66 
getRawLightBrightness(int32_t rawLightId)67 std::optional<std::int32_t> PeripheralController::Light::getRawLightBrightness(int32_t rawLightId) {
68     std::optional<RawLightInfo> rawInfoOpt = context.getRawLightInfo(rawLightId);
69     if (!rawInfoOpt.has_value()) {
70         return std::nullopt;
71     }
72     std::optional<int32_t> brightnessOpt = context.getLightBrightness(rawLightId);
73     if (!brightnessOpt.has_value()) {
74         return std::nullopt;
75     }
76     int brightness = brightnessOpt.value();
77 
78     // If the light node doesn't have max brightness, use the default max brightness.
79     int rawMaxBrightness = rawInfoOpt->maxBrightness.value_or(MAX_BRIGHTNESS);
80     float ratio = static_cast<float>(MAX_BRIGHTNESS) / rawMaxBrightness;
81     // Scale the returned brightness in [0, rawMaxBrightness] to [0, 255]
82     if (rawMaxBrightness != MAX_BRIGHTNESS) {
83         brightness = brightness * ratio;
84     }
85     if (DEBUG_LIGHT_DETAILS) {
86         ALOGD("getRawLightBrightness rawLightId %d brightness 0x%x ratio %.2f", rawLightId,
87               brightness, ratio);
88     }
89     return brightness;
90 }
91 
setRawLightBrightness(int32_t rawLightId,int32_t brightness)92 void PeripheralController::Light::setRawLightBrightness(int32_t rawLightId, int32_t brightness) {
93     std::optional<RawLightInfo> rawInfo = context.getRawLightInfo(rawLightId);
94     if (!rawInfo.has_value()) {
95         return;
96     }
97     // If the light node doesn't have max brightness, use the default max brightness.
98     int rawMaxBrightness = rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS);
99     float ratio = static_cast<float>(MAX_BRIGHTNESS) / rawMaxBrightness;
100     // Scale the requested brightness in [0, 255] to [0, rawMaxBrightness]
101     if (rawMaxBrightness != MAX_BRIGHTNESS) {
102         brightness = ceil(brightness / ratio);
103     }
104     if (DEBUG_LIGHT_DETAILS) {
105         ALOGD("setRawLightBrightness rawLightId %d brightness 0x%x ratio %.2f", rawLightId,
106               brightness, ratio);
107     }
108     context.setLightBrightness(rawLightId, brightness);
109 }
110 
setLightColor(int32_t color)111 bool PeripheralController::MonoLight::setLightColor(int32_t color) {
112     int32_t brightness = getAlpha(color);
113     setRawLightBrightness(rawId, brightness);
114 
115     return true;
116 }
117 
setLightColor(int32_t color)118 bool PeripheralController::RgbLight::setLightColor(int32_t color) {
119     // Compose color value as per:
120     // https://developer.android.com/reference/android/graphics/Color?hl=en
121     // int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);
122     // The alpha component is used to scale the R,G,B leds brightness, with the ratio to
123     // MAX_BRIGHTNESS.
124     brightness = getAlpha(color);
125     int32_t red = 0;
126     int32_t green = 0;
127     int32_t blue = 0;
128     if (brightness > 0) {
129         float ratio = MAX_BRIGHTNESS / brightness;
130         red = ceil(getRed(color) / ratio);
131         green = ceil(getGreen(color) / ratio);
132         blue = ceil(getBlue(color) / ratio);
133     }
134     setRawLightBrightness(rawRgbIds.at(LightColor::RED), red);
135     setRawLightBrightness(rawRgbIds.at(LightColor::GREEN), green);
136     setRawLightBrightness(rawRgbIds.at(LightColor::BLUE), blue);
137     if (rawGlobalId.has_value()) {
138         setRawLightBrightness(rawGlobalId.value(), brightness);
139     }
140 
141     return true;
142 }
143 
setLightColor(int32_t color)144 bool PeripheralController::MultiColorLight::setLightColor(int32_t color) {
145     std::unordered_map<LightColor, int32_t> intensities;
146     intensities.emplace(LightColor::RED, getRed(color));
147     intensities.emplace(LightColor::GREEN, getGreen(color));
148     intensities.emplace(LightColor::BLUE, getBlue(color));
149 
150     context.setLightIntensities(rawId, intensities);
151     setRawLightBrightness(rawId, getAlpha(color));
152     return true;
153 }
154 
getLightColor()155 std::optional<int32_t> PeripheralController::MonoLight::getLightColor() {
156     std::optional<int32_t> brightness = getRawLightBrightness(rawId);
157     if (!brightness.has_value()) {
158         return std::nullopt;
159     }
160 
161     return toArgb(brightness.value(), /*red=*/0, /*green=*/0, /*blue=*/0);
162 }
163 
getLightColor()164 std::optional<int32_t> PeripheralController::RgbLight::getLightColor() {
165     // If the Alpha component is zero, then return color 0.
166     if (brightness == 0) {
167         return 0;
168     }
169     // Compose color value as per:
170     // https://developer.android.com/reference/android/graphics/Color?hl=en
171     // int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);
172     std::optional<int32_t> redOr = getRawLightBrightness(rawRgbIds.at(LightColor::RED));
173     std::optional<int32_t> greenOr = getRawLightBrightness(rawRgbIds.at(LightColor::GREEN));
174     std::optional<int32_t> blueOr = getRawLightBrightness(rawRgbIds.at(LightColor::BLUE));
175     // If we can't get brightness for any of the RGB light
176     if (!redOr.has_value() || !greenOr.has_value() || !blueOr.has_value()) {
177         return std::nullopt;
178     }
179 
180     // Compose the ARGB format color. As the R,G,B color led brightness is scaled by Alpha
181     // value, scale it back to return the nominal color value.
182     float ratio = MAX_BRIGHTNESS / brightness;
183     int32_t red = round(redOr.value() * ratio);
184     int32_t green = round(greenOr.value() * ratio);
185     int32_t blue = round(blueOr.value() * ratio);
186 
187     if (red > MAX_BRIGHTNESS || green > MAX_BRIGHTNESS || blue > MAX_BRIGHTNESS) {
188         // Previously stored brightness isn't valid for current LED values, so just reset to max
189         // brightness since an app couldn't have provided these values in the first place.
190         red = redOr.value();
191         green = greenOr.value();
192         blue = blueOr.value();
193         brightness = MAX_BRIGHTNESS;
194     }
195 
196     return toArgb(brightness, red, green, blue);
197 }
198 
getLightColor()199 std::optional<int32_t> PeripheralController::MultiColorLight::getLightColor() {
200     auto ret = context.getLightIntensities(rawId);
201     if (!ret.has_value()) {
202         return std::nullopt;
203     }
204     std::unordered_map<LightColor, int32_t> intensities = ret.value();
205     // Get red, green, blue colors
206     int32_t color = toArgb(/*brightness=*/0, intensities.at(LightColor::RED),
207                            intensities.at(LightColor::GREEN), intensities.at(LightColor::BLUE));
208     // Get brightness
209     std::optional<int32_t> brightness = getRawLightBrightness(rawId);
210     if (brightness.has_value()) {
211         return toArgb(/*brightness=*/brightness.value(), 0, 0, 0) | color;
212     }
213     return std::nullopt;
214 }
215 
setLightPlayerId(int32_t playerId)216 bool PeripheralController::PlayerIdLight::setLightPlayerId(int32_t playerId) {
217     if (rawLightIds.find(playerId) == rawLightIds.end()) {
218         return false;
219     }
220     for (const auto& [id, rawId] : rawLightIds) {
221         if (playerId == id) {
222             setRawLightBrightness(rawId, MAX_BRIGHTNESS);
223         } else {
224             setRawLightBrightness(rawId, 0);
225         }
226     }
227     return true;
228 }
229 
getLightPlayerId()230 std::optional<int32_t> PeripheralController::PlayerIdLight::getLightPlayerId() {
231     for (const auto& [id, rawId] : rawLightIds) {
232         std::optional<int32_t> brightness = getRawLightBrightness(rawId);
233         if (brightness.has_value() && brightness.value() > 0) {
234             return id;
235         }
236     }
237     return std::nullopt;
238 }
239 
dump(std::string & dump)240 void PeripheralController::MonoLight::dump(std::string& dump) {
241     dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
242 }
243 
dump(std::string & dump)244 void PeripheralController::PlayerIdLight::dump(std::string& dump) {
245     dump += StringPrintf(INDENT4 "PlayerId: %d\n", getLightPlayerId().value_or(-1));
246     dump += StringPrintf(INDENT4 "Raw Player ID LEDs:");
247     for (const auto& [id, rawId] : rawLightIds) {
248         dump += StringPrintf("id %d -> %d ", id, rawId);
249     }
250     dump += "\n";
251 }
252 
dump(std::string & dump)253 void PeripheralController::RgbLight::dump(std::string& dump) {
254     dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
255     dump += StringPrintf(INDENT4 "Raw RGB LEDs: [%d, %d, %d] ", rawRgbIds.at(LightColor::RED),
256                          rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE));
257     if (rawGlobalId.has_value()) {
258         dump += StringPrintf(INDENT4 "Raw Global LED: [%d] ", rawGlobalId.value());
259     }
260     dump += "\n";
261 }
262 
dump(std::string & dump)263 void PeripheralController::MultiColorLight::dump(std::string& dump) {
264     dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0));
265 }
266 
populateDeviceInfo(InputDeviceInfo * deviceInfo)267 void PeripheralController::populateDeviceInfo(InputDeviceInfo* deviceInfo) {
268     // TODO: b/180733860 Remove this after enabling multi-battery
269     if (!mBatteries.empty()) {
270         deviceInfo->setHasBattery(true);
271     }
272 
273     for (const auto& [batteryId, battery] : mBatteries) {
274         InputDeviceBatteryInfo batteryInfo(battery->name, battery->id);
275         deviceInfo->addBatteryInfo(batteryInfo);
276     }
277 
278     for (const auto& [lightId, light] : mLights) {
279         // Input device light doesn't support ordinal, always pass 1.
280         InputDeviceLightInfo lightInfo(light->name, light->id, light->type, light->capabilityFlags,
281                                        /*ordinal=*/1, getPreferredBrightnessLevels(light.get()));
282         deviceInfo->addLightInfo(lightInfo);
283     }
284 }
285 
286 // TODO(b/281822656): Move to constructor and add as a parameter to avoid parsing repeatedly.
287 // Need to change lifecycle of Peripheral controller so that Input device configuration map is
288 // available at construction time before moving this logic to constructor.
getPreferredBrightnessLevels(const Light * light) const289 std::set<BrightnessLevel> PeripheralController::getPreferredBrightnessLevels(
290         const Light* light) const {
291     std::set<BrightnessLevel> levels;
292     if (!isKeyboardBacklightCustomLevelsEnabled() ||
293         light->type != InputDeviceLightType::KEYBOARD_BACKLIGHT) {
294         return levels;
295     }
296     std::optional<std::string> keyboardBacklightLevels =
297             mDeviceContext.getConfiguration().getString("keyboard.backlight.brightnessLevels");
298     if (!keyboardBacklightLevels) {
299         return levels;
300     }
301     std::stringstream ss(*keyboardBacklightLevels);
302     while (ss.good()) {
303         std::string substr;
304         std::getline(ss, substr, ',');
305         char* end;
306         int32_t value = static_cast<int32_t>(strtol(substr.c_str(), &end, 10));
307         if (*end != '\0' || value < 0 || value > 255) {
308             ALOGE("Error parsing keyboard backlight brightness levels, provided levels = %s",
309                   keyboardBacklightLevels->c_str());
310             levels.clear();
311             break;
312         }
313         levels.insert(BrightnessLevel(value));
314     }
315     return levels;
316 }
317 
dump(std::string & dump)318 void PeripheralController::dump(std::string& dump) {
319     dump += INDENT2 "Input Controller:\n";
320     if (!mLights.empty()) {
321         dump += INDENT3 "Lights:\n";
322         for (const auto& [lightId, light] : mLights) {
323             dump += StringPrintf(INDENT4 "Id: %d", lightId);
324             dump += StringPrintf(INDENT4 "Name: %s", light->name.c_str());
325             dump += StringPrintf(INDENT4 "Type: %s", ftl::enum_string(light->type).c_str());
326             dump += StringPrintf(INDENT4 "Capability flags: %s",
327                                  light->capabilityFlags.string().c_str());
328             light->dump(dump);
329         }
330     }
331     // Dump raw lights
332     dump += INDENT3 "RawLights:\n";
333     dump += INDENT4 "Id:\t Name:\t Flags:\t Max brightness:\t Brightness\n";
334     const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds();
335     // Map from raw light id to raw light info
336     std::unordered_map<int32_t, RawLightInfo> rawInfos;
337     for (const auto& rawId : rawLightIds) {
338         std::optional<RawLightInfo> rawInfo = getDeviceContext().getRawLightInfo(rawId);
339         if (!rawInfo.has_value()) {
340             continue;
341         }
342         dump += StringPrintf(INDENT4 "%d", rawId);
343         dump += StringPrintf(INDENT4 "%s", rawInfo->name.c_str());
344         dump += StringPrintf(INDENT4 "%s", rawInfo->flags.string().c_str());
345         dump += StringPrintf(INDENT4 "%d", rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS));
346         dump += StringPrintf(INDENT4 "%d\n",
347                              getDeviceContext().getLightBrightness(rawId).value_or(-1));
348     }
349 
350     if (!mBatteries.empty()) {
351         dump += INDENT3 "Batteries:\n";
352         for (const auto& [batteryId, battery] : mBatteries) {
353             dump += StringPrintf(INDENT4 "Id: %d", batteryId);
354             dump += StringPrintf(INDENT4 "Name: %s", battery->name.c_str());
355             dump += getBatteryCapacity(batteryId).has_value()
356                     ? StringPrintf(INDENT3 "Capacity: %d\n", getBatteryCapacity(batteryId).value())
357                     : StringPrintf(INDENT3 "Capacity: Unknown");
358 
359             std::string status;
360             switch (getBatteryStatus(batteryId).value_or(BATTERY_STATUS_UNKNOWN)) {
361                 case BATTERY_STATUS_CHARGING:
362                     status = "Charging";
363                     break;
364                 case BATTERY_STATUS_DISCHARGING:
365                     status = "Discharging";
366                     break;
367                 case BATTERY_STATUS_NOT_CHARGING:
368                     status = "Not charging";
369                     break;
370                 case BATTERY_STATUS_FULL:
371                     status = "Full";
372                     break;
373                 default:
374                     status = "Unknown";
375             }
376             dump += StringPrintf(INDENT3 "Status: %s\n", status.c_str());
377         }
378     }
379 }
380 
configureBattries()381 void PeripheralController::configureBattries() {
382     // Check raw batteries
383     const std::vector<int32_t> rawBatteryIds = getDeviceContext().getRawBatteryIds();
384 
385     for (const auto& rawId : rawBatteryIds) {
386         std::optional<RawBatteryInfo> rawInfo = getDeviceContext().getRawBatteryInfo(rawId);
387         if (!rawInfo.has_value()) {
388             continue;
389         }
390         std::unique_ptr<Battery> battery =
391                 std::make_unique<Battery>(getDeviceContext(), rawInfo->name, rawInfo->id);
392         mBatteries.insert_or_assign(rawId, std::move(battery));
393     }
394 }
395 
configureLights()396 void PeripheralController::configureLights() {
397     bool hasRedLed = false;
398     bool hasGreenLed = false;
399     bool hasBlueLed = false;
400     std::optional<int32_t> rawGlobalId = std::nullopt;
401     // Player ID light common name string
402     std::string playerIdName;
403     // Raw RGB color to raw light ID
404     std::unordered_map<LightColor, int32_t /* rawLightId */> rawRgbIds;
405     // Map from player Id to raw light Id
406     std::unordered_map<int32_t, int32_t> playerIdLightIds;
407     // Set of Keyboard backlights
408     std::set<int32_t> keyboardBacklightIds;
409 
410     // Check raw lights
411     const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds();
412     // Map from raw light id to raw light info
413     std::unordered_map<int32_t, RawLightInfo> rawInfos;
414     for (const auto& rawId : rawLightIds) {
415         std::optional<RawLightInfo> rawInfo = getDeviceContext().getRawLightInfo(rawId);
416         if (!rawInfo.has_value()) {
417             continue;
418         }
419         rawInfos.insert_or_assign(rawId, rawInfo.value());
420         // Check if this is a group LEDs for player ID
421         // The name for the light has already been parsed and is the `function`
422         // value; for player ID lights the function is expected to be `player-#`.
423         // However, the Sony driver will use `sony#` instead on SIXAXIS
424         // gamepads.
425         std::regex lightPattern("(player|sony)-?([0-9]+)");
426         std::smatch results;
427         if (std::regex_match(rawInfo->name, results, lightPattern)) {
428             std::string commonName = results[1].str();
429             int32_t playerId = std::stoi(results[2]);
430             if (playerIdLightIds.empty()) {
431                 playerIdName = commonName;
432                 playerIdLightIds.insert_or_assign(playerId, rawId);
433             } else {
434                 // Make sure the player ID leds have common string name
435                 if (playerIdName.compare(commonName) == 0 &&
436                     playerIdLightIds.find(playerId) == playerIdLightIds.end()) {
437                     playerIdLightIds.insert_or_assign(playerId, rawId);
438                 }
439             }
440         }
441         // Check if this is a Keyboard backlight
442         if (rawInfo->flags.test(InputLightClass::KEYBOARD_BACKLIGHT)) {
443             keyboardBacklightIds.insert(rawId);
444         }
445         // Check if this is an LED of RGB light
446         if (rawInfo->flags.test(InputLightClass::RED)) {
447             hasRedLed = true;
448             rawRgbIds.emplace(LightColor::RED, rawId);
449         }
450         if (rawInfo->flags.test(InputLightClass::GREEN)) {
451             hasGreenLed = true;
452             rawRgbIds.emplace(LightColor::GREEN, rawId);
453         }
454         if (rawInfo->flags.test(InputLightClass::BLUE)) {
455             hasBlueLed = true;
456             rawRgbIds.emplace(LightColor::BLUE, rawId);
457         }
458         if (rawInfo->flags.test(InputLightClass::GLOBAL)) {
459             rawGlobalId = rawId;
460         }
461         if (DEBUG_LIGHT_DETAILS) {
462             ALOGD("Light rawId %d name %s max %d flags %s \n", rawInfo->id, rawInfo->name.c_str(),
463                   rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS), rawInfo->flags.string().c_str());
464         }
465     }
466 
467     // Construct a player ID light
468     if (playerIdLightIds.size() > 1) {
469         std::unique_ptr<Light> light =
470                 std::make_unique<PlayerIdLight>(getDeviceContext(), playerIdName, ++mNextId,
471                                                 playerIdLightIds);
472         mLights.insert_or_assign(light->id, std::move(light));
473         // Remove these raw lights from raw light info as they've been used to compose a
474         // Player ID light, so we do not expose these raw lights as mono lights.
475         for (const auto& [playerId, rawId] : playerIdLightIds) {
476             rawInfos.erase(rawId);
477         }
478     }
479     // Construct a RGB light for composed RGB light
480     if (hasRedLed && hasGreenLed && hasBlueLed) {
481         if (DEBUG_LIGHT_DETAILS) {
482             ALOGD("Rgb light ids [%d, %d, %d] \n", rawRgbIds.at(LightColor::RED),
483                   rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE));
484         }
485         bool isKeyboardBacklight = keyboardBacklightIds.find(rawRgbIds.at(LightColor::RED)) !=
486                         keyboardBacklightIds.end() &&
487                 keyboardBacklightIds.find(rawRgbIds.at(LightColor::GREEN)) !=
488                         keyboardBacklightIds.end() &&
489                 keyboardBacklightIds.find(rawRgbIds.at(LightColor::BLUE)) !=
490                         keyboardBacklightIds.end() &&
491                 (!rawGlobalId.has_value() ||
492                  keyboardBacklightIds.find(rawGlobalId.value()) != keyboardBacklightIds.end());
493 
494         std::unique_ptr<Light> light =
495                 std::make_unique<RgbLight>(getDeviceContext(), ++mNextId,
496                                            isKeyboardBacklight
497                                                    ? InputDeviceLightType::KEYBOARD_BACKLIGHT
498                                                    : InputDeviceLightType::INPUT,
499                                            rawRgbIds, rawGlobalId);
500         mLights.insert_or_assign(light->id, std::move(light));
501         // Remove from raw light info as they've been composed a RBG light.
502         rawInfos.erase(rawRgbIds.at(LightColor::RED));
503         rawInfos.erase(rawRgbIds.at(LightColor::GREEN));
504         rawInfos.erase(rawRgbIds.at(LightColor::BLUE));
505         if (rawGlobalId.has_value()) {
506             rawInfos.erase(rawGlobalId.value());
507         }
508     }
509 
510     // Check the rest of raw light infos
511     for (const auto& [rawId, rawInfo] : rawInfos) {
512         InputDeviceLightType type;
513         if (keyboardBacklightIds.find(rawId) != keyboardBacklightIds.end()) {
514             type = InputDeviceLightType::KEYBOARD_BACKLIGHT;
515         } else if (rawInfo.flags.test(InputLightClass::KEYBOARD_MIC_MUTE)) {
516             type = InputDeviceLightType::KEYBOARD_MIC_MUTE;
517         } else {
518             type = InputDeviceLightType::INPUT;
519         }
520 
521         // If the node is multi-color led, construct a MULTI_COLOR light
522         if (rawInfo.flags.test(InputLightClass::MULTI_INDEX) &&
523             rawInfo.flags.test(InputLightClass::MULTI_INTENSITY)) {
524             if (DEBUG_LIGHT_DETAILS) {
525                 ALOGD("Multicolor light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str());
526             }
527             std::unique_ptr<Light> light =
528                     std::make_unique<MultiColorLight>(getDeviceContext(), rawInfo.name, ++mNextId,
529                                                       type, rawInfo.id);
530             mLights.insert_or_assign(light->id, std::move(light));
531             continue;
532         }
533         // Construct a Mono LED light
534         if (DEBUG_LIGHT_DETAILS) {
535             ALOGD("Mono light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str());
536         }
537         std::unique_ptr<Light> light = std::make_unique<MonoLight>(getDeviceContext(), rawInfo.name,
538                                                                    ++mNextId, type, rawInfo.id);
539 
540         mLights.insert_or_assign(light->id, std::move(light));
541     }
542 }
543 
getBatteryCapacity(int batteryId)544 std::optional<int32_t> PeripheralController::getBatteryCapacity(int batteryId) {
545     return getDeviceContext().getBatteryCapacity(batteryId);
546 }
547 
getBatteryStatus(int batteryId)548 std::optional<int32_t> PeripheralController::getBatteryStatus(int batteryId) {
549     return getDeviceContext().getBatteryStatus(batteryId);
550 }
551 
setLightColor(int32_t lightId,int32_t color)552 bool PeripheralController::setLightColor(int32_t lightId, int32_t color) {
553     auto it = mLights.find(lightId);
554     if (it == mLights.end()) {
555         return false;
556     }
557     auto& light = it->second;
558     if (DEBUG_LIGHT_DETAILS) {
559         ALOGD("setLightColor lightId %d type %s color 0x%x", lightId,
560               ftl::enum_string(light->type).c_str(), color);
561     }
562     return light->setLightColor(color);
563 }
564 
getLightColor(int32_t lightId)565 std::optional<int32_t> PeripheralController::getLightColor(int32_t lightId) {
566     auto it = mLights.find(lightId);
567     if (it == mLights.end()) {
568         return std::nullopt;
569     }
570     auto& light = it->second;
571     std::optional<int32_t> color = light->getLightColor();
572     if (DEBUG_LIGHT_DETAILS) {
573         ALOGD("getLightColor lightId %d type %s color 0x%x", lightId,
574               ftl::enum_string(light->type).c_str(), color.value_or(0));
575     }
576     return color;
577 }
578 
setLightPlayerId(int32_t lightId,int32_t playerId)579 bool PeripheralController::setLightPlayerId(int32_t lightId, int32_t playerId) {
580     auto it = mLights.find(lightId);
581     if (it == mLights.end()) {
582         return false;
583     }
584     auto& light = it->second;
585     return light->setLightPlayerId(playerId);
586 }
587 
getLightPlayerId(int32_t lightId)588 std::optional<int32_t> PeripheralController::getLightPlayerId(int32_t lightId) {
589     auto it = mLights.find(lightId);
590     if (it == mLights.end()) {
591         return std::nullopt;
592     }
593     auto& light = it->second;
594     return light->getLightPlayerId();
595 }
596 
getEventHubId() const597 int32_t PeripheralController::getEventHubId() const {
598     return getDeviceContext().getEventHubId();
599 }
600 } // namespace android
601