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