blob: 5683e6901a31aa9a6555b253c39cb7ef28a05161 [file] [log] [blame]
Santos Cordon3107d292016-09-20 15:50:35 -07001/* * Copyright (C) 2008 The Android Open Source Project
Mike Lockwood3a322132009-11-24 00:30:52 -05002 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
Adam Lesinski182f73f2013-12-05 16:48:06 -080016package com.android.server.lights;
17
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +010018import android.Manifest;
19import android.annotation.Nullable;
Ruben Brunk49506e02016-04-18 18:10:47 -070020import android.app.ActivityManager;
Mike Lockwood3a322132009-11-24 00:30:52 -050021import android.content.Context;
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +010022import android.hardware.light.HwLight;
23import android.hardware.light.HwLightState;
24import android.hardware.light.ILights;
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +010025import android.hardware.lights.ILightsManager;
26import android.hardware.lights.Light;
27import android.hardware.lights.LightState;
Mike Lockwood3a322132009-11-24 00:30:52 -050028import android.os.Handler;
Dan Gittik832b4972019-02-13 18:17:47 +000029import android.os.IBinder;
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +010030import android.os.Looper;
Dan Gittik832b4972019-02-13 18:17:47 +000031import android.os.PowerManager;
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +010032import android.os.RemoteException;
33import android.os.ServiceManager;
Jeff Brown3edf5272014-08-14 19:25:14 -070034import android.os.Trace;
Ruben Brunk49506e02016-04-18 18:10:47 -070035import android.provider.Settings;
Joe Onorato8a9b2202010-02-26 18:56:32 -080036import android.util.Slog;
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +010037import android.util.SparseArray;
Dan Gittik832b4972019-02-13 18:17:47 +000038import android.view.SurfaceControl;
39
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +010040import com.android.internal.annotations.GuardedBy;
41import com.android.internal.annotations.VisibleForTesting;
42import com.android.internal.util.Preconditions;
Dan Gittik832b4972019-02-13 18:17:47 +000043import com.android.server.SystemService;
Mike Lockwood3a322132009-11-24 00:30:52 -050044
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +010045import java.util.ArrayList;
46import java.util.HashMap;
47import java.util.List;
48import java.util.Map;
49
Adam Lesinski182f73f2013-12-05 16:48:06 -080050public class LightsService extends SystemService {
51 static final String TAG = "LightsService";
52 static final boolean DEBUG = false;
Mike Lockwood3a322132009-11-24 00:30:52 -050053
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +010054 private LightImpl[] mLights = null;
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +010055 private SparseArray<LightImpl> mLightsById = null;
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +010056
57 private ILights mVintfLights = null;
Mike Lockwood3a322132009-11-24 00:30:52 -050058
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +010059 @VisibleForTesting
60 final LightsManagerBinderService mManagerService;
61
62 private Handler mH;
63
64 private final class LightsManagerBinderService extends ILightsManager.Stub {
65
66 private final class Session {
67 final IBinder mToken;
68 final SparseArray<LightState> mRequests = new SparseArray<>();
69
70 Session(IBinder token) {
71 mToken = token;
72 }
73
74 void setRequest(int lightId, LightState state) {
75 if (state != null) {
76 mRequests.put(lightId, state);
77 } else {
78 mRequests.remove(lightId);
79 }
80 }
81 }
82
83 @GuardedBy("LightsService.this")
84 private final List<Session> mSessions = new ArrayList<>();
85
86 /**
87 * Returns the lights available for apps to control on the device. Only lights that aren't
88 * reserved for system use are available to apps.
89 */
90 @Override
91 public List<Light> getLights() {
92 getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
93 "getLights requires CONTROL_DEVICE_LIGHTS_PERMISSION");
94
95 synchronized (LightsService.this) {
96 final List<Light> lights = new ArrayList<Light>();
97 for (int i = 0; i < mLightsById.size(); i++) {
98 HwLight hwLight = mLightsById.valueAt(i).getHwLight();
99 if (!isSystemLight(hwLight)) {
100 lights.add(new Light(hwLight.id, hwLight.ordinal, hwLight.type));
101 }
102 }
103 return lights;
104 }
105 }
106
107 /**
108 * Updates the set of light requests for {@param token} with additions and removals from
109 * {@param lightIds} and {@param lightStates}.
110 *
111 * <p>Null values mean that the request should be removed, and the light turned off if it
112 * is not being used by anything else.
113 */
114 @Override
115 public void setLightStates(IBinder token, int[] lightIds, LightState[] lightStates) {
116 getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
117 "setLightStates requires CONTROL_DEVICE_LIGHTS permission");
118 Preconditions.checkState(lightIds.length == lightStates.length);
119
120 synchronized (LightsService.this) {
121 Session session = getSessionLocked(Preconditions.checkNotNull(token));
122 Preconditions.checkState(session != null, "not registered");
123
124 checkRequestIsValid(lightIds);
125
126 for (int i = 0; i < lightIds.length; i++) {
127 session.setRequest(lightIds[i], lightStates[i]);
128 }
129 invalidateLightStatesLocked();
130 }
131 }
132
133 @Override
134 public @Nullable LightState getLightState(int lightId) {
135 getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
136 "getLightState(@TestApi) requires CONTROL_DEVICE_LIGHTS permission");
137
138 synchronized (LightsService.this) {
139 final LightImpl light = mLightsById.get(lightId);
140 if (light == null || isSystemLight(light.getHwLight())) {
141 throw new IllegalArgumentException("Invalid light: " + lightId);
142 }
143 return new LightState(light.getColor());
144 }
145 }
146
147 @Override
148 public void openSession(IBinder token) {
149 getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
150 "openSession requires CONTROL_DEVICE_LIGHTS permission");
151 Preconditions.checkNotNull(token);
152
153 synchronized (LightsService.this) {
154 Preconditions.checkState(getSessionLocked(token) == null, "already registered");
155 try {
156 token.linkToDeath(() -> closeSessionInternal(token), 0);
157 mSessions.add(new Session(token));
158 } catch (RemoteException e) {
159 Slog.e(TAG, "Couldn't open session, client already died" , e);
160 throw new IllegalArgumentException("Client is already dead.");
161 }
162 }
163 }
164
165 @Override
166 public void closeSession(IBinder token) {
167 getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
168 "closeSession requires CONTROL_DEVICE_LIGHTS permission");
169 Preconditions.checkNotNull(token);
170 closeSessionInternal(token);
171 }
172
173 private void closeSessionInternal(IBinder token) {
174 synchronized (LightsService.this) {
175 final Session session = getSessionLocked(token);
176 if (session != null) {
177 mSessions.remove(session);
178 invalidateLightStatesLocked();
179 }
180 }
181 }
182
183 private void checkRequestIsValid(int[] lightIds) {
184 for (int i = 0; i < lightIds.length; i++) {
185 final LightImpl light = mLightsById.get(lightIds[i]);
186 final HwLight hwLight = light.getHwLight();
187 Preconditions.checkState(light != null && !isSystemLight(hwLight),
188 "invalid lightId " + hwLight.id);
189 }
190 }
191
192 /**
193 * Apply light state requests for all light IDs.
194 *
195 * <p>In case of conflict, the session that started earliest wins.
196 */
197 private void invalidateLightStatesLocked() {
198 final Map<Integer, LightState> states = new HashMap<>();
199 for (int i = mSessions.size() - 1; i >= 0; i--) {
200 SparseArray<LightState> requests = mSessions.get(i).mRequests;
201 for (int j = 0; j < requests.size(); j++) {
202 states.put(requests.keyAt(j), requests.valueAt(j));
203 }
204 }
205 for (int i = 0; i < mLightsById.size(); i++) {
206 LightImpl light = mLightsById.valueAt(i);
207 HwLight hwLight = light.getHwLight();
208 if (!isSystemLight(hwLight)) {
209 LightState state = states.get(hwLight.id);
210 if (state != null) {
211 light.setColor(state.getColor());
212 } else {
213 light.turnOff();
214 }
215 }
216 }
217 }
218
219 private @Nullable Session getSessionLocked(IBinder token) {
220 for (int i = 0; i < mSessions.size(); i++) {
221 if (token.equals(mSessions.get(i).mToken)) {
222 return mSessions.get(i);
223 }
224 }
225 return null;
226 }
227 }
228
Ivailo Karamanolevf773e102020-01-16 16:10:42 +0100229 private final class LightImpl extends LogicalLight {
Dan Gittik832b4972019-02-13 18:17:47 +0000230 private final IBinder mDisplayToken;
231 private final int mSurfaceControlMaximumBrightness;
232
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +0100233 private LightImpl(Context context, HwLight hwLight) {
234 mHwLight = hwLight;
Dan Gittik832b4972019-02-13 18:17:47 +0000235 mDisplayToken = SurfaceControl.getInternalDisplayToken();
236 final boolean brightnessSupport = SurfaceControl.getDisplayBrightnessSupport(
237 mDisplayToken);
238 if (DEBUG) {
239 Slog.d(TAG, "Display brightness support: " + brightnessSupport);
240 }
241 int maximumBrightness = 0;
242 if (brightnessSupport) {
243 PowerManager pm = context.getSystemService(PowerManager.class);
244 if (pm != null) {
245 maximumBrightness = pm.getMaximumScreenBrightnessSetting();
246 }
247 }
248 mSurfaceControlMaximumBrightness = maximumBrightness;
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500249 }
250
Adam Lesinski182f73f2013-12-05 16:48:06 -0800251 @Override
Santos Cordon4505e5e2020-01-17 15:18:10 +0000252 public void setBrightnessFloat(float brightness) {
253 if (!Float.isNaN(brightness)) {
254 setBrightness(brightness, 0, BRIGHTNESS_MODE_USER);
255 }
256 }
257
258 @Override
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500259 public void setBrightness(int brightness) {
260 setBrightness(brightness, BRIGHTNESS_MODE_USER);
261 }
262
Adam Lesinski182f73f2013-12-05 16:48:06 -0800263 @Override
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500264 public void setBrightness(int brightness, int brightnessMode) {
Santos Cordon4505e5e2020-01-17 15:18:10 +0000265 setBrightness(Float.NaN, brightness, brightnessMode);
266 }
267
268 private void setBrightness(float brightnessFloat, int brightness, int brightnessMode) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500269 synchronized (this) {
Santos Cordon3107d292016-09-20 15:50:35 -0700270 // LOW_PERSISTENCE cannot be manually set
271 if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +0100272 Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mHwLight.id
273 + ": brightness=0x" + Integer.toHexString(brightness));
Santos Cordon3107d292016-09-20 15:50:35 -0700274 return;
275 }
Dan Gittik832b4972019-02-13 18:17:47 +0000276 // Ideally, we'd like to set the brightness mode through the SF/HWC as well, but
277 // right now we just fall back to the old path through Lights brightessMode is
278 // anything but USER or the device shouldBeInLowPersistenceMode().
279 if (brightnessMode == BRIGHTNESS_MODE_USER && !shouldBeInLowPersistenceMode()
280 && mSurfaceControlMaximumBrightness == 255) {
281 // TODO: the last check should be mSurfaceControlMaximumBrightness != 0; the
282 // reason we enforce 255 right now is to stay consistent with the old path. In
283 // the future, the framework should be refactored so that brightness is a float
284 // between 0.0f and 1.0f, and the actual number of supported brightness levels
285 // is determined in the device-specific implementation.
286 if (DEBUG) {
287 Slog.d(TAG, "Using new setBrightness path!");
288 }
Santos Cordon4505e5e2020-01-17 15:18:10 +0000289
290 if (!Float.isNaN(brightnessFloat)) {
291 SurfaceControl.setDisplayBrightness(mDisplayToken, brightnessFloat);
292 } else if (brightness == 0) {
Fiona Campbell466dc042019-11-22 12:29:44 +0000293 SurfaceControl.setDisplayBrightness(mDisplayToken, -1.0f);
294 } else {
295 SurfaceControl.setDisplayBrightness(mDisplayToken,
296 (float) (brightness - 1) / (mSurfaceControlMaximumBrightness - 1));
297 }
Dan Gittik832b4972019-02-13 18:17:47 +0000298 } else {
299 int color = brightness & 0x000000ff;
300 color = 0xff000000 | (color << 16) | (color << 8) | color;
301 setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
302 }
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500303 }
304 }
305
Adam Lesinski182f73f2013-12-05 16:48:06 -0800306 @Override
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500307 public void setColor(int color) {
308 synchronized (this) {
309 setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0);
310 }
311 }
312
Adam Lesinski182f73f2013-12-05 16:48:06 -0800313 @Override
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500314 public void setFlashing(int color, int mode, int onMS, int offMS) {
315 synchronized (this) {
316 setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER);
317 }
318 }
319
Adam Lesinski182f73f2013-12-05 16:48:06 -0800320 @Override
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500321 public void pulse() {
Mike Lockwood670f9322010-01-20 12:13:36 -0500322 pulse(0x00ffffff, 7);
323 }
324
Adam Lesinski182f73f2013-12-05 16:48:06 -0800325 @Override
Mike Lockwood670f9322010-01-20 12:13:36 -0500326 public void pulse(int color, int onMS) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500327 synchronized (this) {
328 if (mColor == 0 && !mFlashing) {
Santos Cordon3107d292016-09-20 15:50:35 -0700329 setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000,
330 BRIGHTNESS_MODE_USER);
Oskar Anderoe8467192013-12-03 17:41:27 +0100331 mColor = 0;
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +0100332 mH.postDelayed(this::stopFlashing, onMS);
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500333 }
334 }
335 }
336
Adam Lesinski182f73f2013-12-05 16:48:06 -0800337 @Override
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500338 public void turnOff() {
339 synchronized (this) {
340 setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0);
341 }
342 }
343
Santos Cordon3107d292016-09-20 15:50:35 -0700344 @Override
345 public void setVrMode(boolean enabled) {
346 synchronized (this) {
347 if (mVrModeEnabled != enabled) {
348 mVrModeEnabled = enabled;
Ruben Brunk8ad3f202015-12-28 14:45:11 -0800349
Santos Cordon3107d292016-09-20 15:50:35 -0700350 mUseLowPersistenceForVR =
351 (getVrDisplayMode() == Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE);
352 if (shouldBeInLowPersistenceMode()) {
353 mLastBrightnessMode = mBrightnessMode;
354 }
355
356 // NOTE: We do not trigger a call to setLightLocked here. We do not know the
357 // current brightness or other values when leaving VR so we avoid any incorrect
358 // jumps. The code that calls this method will immediately issue a brightness
359 // update which is when the change will occur.
360 }
Ruben Brunk8ad3f202015-12-28 14:45:11 -0800361 }
362 }
363
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500364 private void stopFlashing() {
365 synchronized (this) {
366 setLightLocked(mColor, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_USER);
367 }
368 }
369
370 private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
Santos Cordon3107d292016-09-20 15:50:35 -0700371 if (shouldBeInLowPersistenceMode()) {
372 brightnessMode = BRIGHTNESS_MODE_LOW_PERSISTENCE;
373 } else if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
374 brightnessMode = mLastBrightnessMode;
375 }
376
Oleksiy Avramchenko4f4939f2017-04-25 12:30:49 +0200377 if (!mInitialized || color != mColor || mode != mMode || onMS != mOnMS ||
378 offMS != mOffMS || mBrightnessMode != brightnessMode) {
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +0100379 if (DEBUG) {
380 Slog.v(TAG, "setLight #" + mHwLight.id + ": color=#"
381 + Integer.toHexString(color) + ": brightnessMode=" + brightnessMode);
382 }
Oleksiy Avramchenko4f4939f2017-04-25 12:30:49 +0200383 mInitialized = true;
Ruben Brunk8ad3f202015-12-28 14:45:11 -0800384 mLastColor = mColor;
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500385 mColor = color;
386 mMode = mode;
387 mOnMS = onMS;
388 mOffMS = offMS;
Ruben Brunk8ad3f202015-12-28 14:45:11 -0800389 mBrightnessMode = brightnessMode;
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +0100390 setLightUnchecked(color, mode, onMS, offMS, brightnessMode);
391 }
392 }
393
394 private void setLightUnchecked(int color, int mode, int onMS, int offMS,
395 int brightnessMode) {
396 Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLightState(" + mHwLight.id + ", 0x"
397 + Integer.toHexString(color) + ")");
398 if (mVintfLights != null) {
399 HwLightState lightState = new HwLightState();
400 lightState.color = color;
401 lightState.flashMode = (byte) mode;
402 lightState.flashOnMs = onMS;
403 lightState.flashOffMs = offMS;
404 lightState.brightnessMode = (byte) brightnessMode;
Jeff Brown3edf5272014-08-14 19:25:14 -0700405 try {
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +0100406 mVintfLights.setLightState(mHwLight.id, lightState);
407 } catch (RemoteException | UnsupportedOperationException ex) {
408 Slog.e(TAG, "Failed issuing setLightState", ex);
409 } finally {
410 Trace.traceEnd(Trace.TRACE_TAG_POWER);
411 }
412 } else {
413 try {
414 setLight_native(mHwLight.id, color, mode, onMS, offMS, brightnessMode);
Jeff Brown3edf5272014-08-14 19:25:14 -0700415 } finally {
416 Trace.traceEnd(Trace.TRACE_TAG_POWER);
417 }
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500418 }
419 }
420
Santos Cordon3107d292016-09-20 15:50:35 -0700421 private boolean shouldBeInLowPersistenceMode() {
422 return mVrModeEnabled && mUseLowPersistenceForVR;
423 }
424
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +0100425 private HwLight getHwLight() {
426 return mHwLight;
427 }
428
429 private int getColor() {
430 return mColor;
431 }
432
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +0100433 private HwLight mHwLight;
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500434 private int mColor;
435 private int mMode;
436 private int mOnMS;
437 private int mOffMS;
438 private boolean mFlashing;
Ruben Brunk8ad3f202015-12-28 14:45:11 -0800439 private int mBrightnessMode;
440 private int mLastBrightnessMode;
441 private int mLastColor;
Santos Cordon3107d292016-09-20 15:50:35 -0700442 private boolean mVrModeEnabled;
443 private boolean mUseLowPersistenceForVR;
Oleksiy Avramchenko4f4939f2017-04-25 12:30:49 +0200444 private boolean mInitialized;
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500445 }
Mike Lockwood3a322132009-11-24 00:30:52 -0500446
Jeff Brownb880d882014-02-10 19:47:07 -0800447 public LightsService(Context context) {
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +0100448 this(context,
449 ILights.Stub.asInterface(
450 ServiceManager.getService("android.hardware.light.ILights/default")),
451 Looper.myLooper());
452 }
453
454 @VisibleForTesting
455 LightsService(Context context, ILights service, Looper looper) {
Jeff Brownb880d882014-02-10 19:47:07 -0800456 super(context);
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +0100457 mH = new Handler(looper);
458 mVintfLights = service;
459 mManagerService = new LightsManagerBinderService();
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +0100460 populateAvailableLights(context);
461 }
462
463 private void populateAvailableLights(Context context) {
464 mLights = new LightImpl[LightsManager.LIGHT_ID_COUNT];
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +0100465 mLightsById = new SparseArray<>();
466
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +0100467 if (mVintfLights != null) {
468 try {
469 for (HwLight availableLight : mVintfLights.getLights()) {
470 LightImpl light = new LightImpl(context, availableLight);
471 int type = (int) availableLight.type;
472 if (0 <= type && type < mLights.length && mLights[type] == null) {
473 mLights[type] = light;
474 }
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +0100475 mLightsById.put(availableLight.id, light);
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +0100476 }
477 } catch (RemoteException ex) {
478 Slog.e(TAG, "Unable to get lights for initialization", ex);
479 }
480 }
481
482 // In the case where only the old HAL is available, all lights will be initialized here
483 for (int i = 0; i < mLights.length; i++) {
484 if (mLights[i] == null) {
485 // The ordinal can be anything if there is only 1 light of each type. Set it to 1.
486 HwLight light = new HwLight();
487 light.id = (byte) i;
488 light.ordinal = 1;
489 light.type = (byte) i;
490
491 mLights[i] = new LightImpl(context, light);
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +0100492 mLightsById.put(i, mLights[i]);
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +0100493 }
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500494 }
Mike Lockwood3a322132009-11-24 00:30:52 -0500495 }
496
Adam Lesinski182f73f2013-12-05 16:48:06 -0800497 @Override
498 public void onStart() {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800499 publishLocalService(LightsManager.class, mService);
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +0100500 publishBinderService(Context.LIGHTS_SERVICE, mManagerService);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800501 }
502
Ruben Brunk8ad3f202015-12-28 14:45:11 -0800503 @Override
504 public void onBootPhase(int phase) {
Ruben Brunk8ad3f202015-12-28 14:45:11 -0800505 }
506
Ruben Brunk49506e02016-04-18 18:10:47 -0700507 private int getVrDisplayMode() {
508 int currentUser = ActivityManager.getCurrentUser();
509 return Settings.Secure.getIntForUser(getContext().getContentResolver(),
510 Settings.Secure.VR_DISPLAY_MODE,
511 /*default*/Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE,
512 currentUser);
513 }
514
Adam Lesinski182f73f2013-12-05 16:48:06 -0800515 private final LightsManager mService = new LightsManager() {
516 @Override
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +0100517 public LogicalLight getLight(int lightType) {
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +0100518 if (mLights != null && 0 <= lightType && lightType < mLights.length) {
Ivailo Karamanolevc176fb82019-12-02 10:41:25 +0100519 return mLights[lightType];
Adam Lesinski182f73f2013-12-05 16:48:06 -0800520 } else {
521 return null;
522 }
523 }
524 };
525
Ivailo Karamanolev090d02c2020-01-09 17:02:49 +0100526 /**
527 * Returns whether a light is system-use-only or should be accessible to
528 * applications using the {@link android.hardware.lights.LightsManager} API.
529 */
530 private static boolean isSystemLight(HwLight light) {
531 // LIGHT_ID_COUNT comes from the 2.0 HIDL HAL and only contains system
532 // lights. Newly added lights will be made available via the
533 // LightsManager API.
534 return 0 <= light.type && light.type < LightsManager.LIGHT_ID_COUNT;
535 }
Mike Lockwood3a322132009-11-24 00:30:52 -0500536
Steven Moreland8b9ec4f2016-10-04 17:25:52 -0700537 static native void setLight_native(int light, int color, int mode,
Mike Lockwood3a322132009-11-24 00:30:52 -0500538 int onMS, int offMS, int brightnessMode);
Mike Lockwood3a322132009-11-24 00:30:52 -0500539}