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 package android.hardware.lights; 18 19 import android.Manifest; 20 import android.annotation.NonNull; 21 import android.annotation.RequiresPermission; 22 import android.content.Context; 23 import android.hardware.lights.LightsManager.LightsSession; 24 import android.os.RemoteException; 25 import android.os.ServiceManager; 26 import android.os.ServiceManager.ServiceNotFoundException; 27 import android.util.CloseGuard; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.internal.util.Preconditions; 31 32 import java.lang.ref.Reference; 33 import java.util.List; 34 35 /** 36 * The LightsManager class allows control over device lights. 37 * 38 * @hide 39 */ 40 public final class SystemLightsManager extends LightsManager { 41 private static final String TAG = "LightsManager"; 42 43 @NonNull private final ILightsManager mService; 44 45 /** 46 * Creates a SystemLightsManager. 47 * 48 * @hide 49 */ SystemLightsManager(@onNull Context context)50 public SystemLightsManager(@NonNull Context context) throws ServiceNotFoundException { 51 this(context, ILightsManager.Stub.asInterface( 52 ServiceManager.getServiceOrThrow(Context.LIGHTS_SERVICE))); 53 } 54 55 /** 56 * Creates a SystemLightsManager with a provided service implementation. 57 * 58 * @hide 59 */ 60 @VisibleForTesting SystemLightsManager(@onNull Context context, @NonNull ILightsManager service)61 public SystemLightsManager(@NonNull Context context, @NonNull ILightsManager service) { 62 mService = Preconditions.checkNotNull(service); 63 } 64 65 /** 66 * Returns the lights available on the device. 67 * 68 * @return A list of available lights 69 */ 70 @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS) 71 @Override getLights()72 public @NonNull List<Light> getLights() { 73 try { 74 return mService.getLights(); 75 } catch (RemoteException e) { 76 throw e.rethrowFromSystemServer(); 77 } 78 } 79 80 /** 81 * Returns the state of a specified light. 82 * 83 * @hide 84 */ 85 @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS) 86 @Override getLightState(@onNull Light light)87 public @NonNull LightState getLightState(@NonNull Light light) { 88 Preconditions.checkNotNull(light); 89 try { 90 return mService.getLightState(light.getId()); 91 } catch (RemoteException e) { 92 throw e.rethrowFromSystemServer(); 93 } 94 } 95 96 /** 97 * Creates a new LightsSession that can be used to control the device lights. 98 */ 99 @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS) 100 @Override openSession()101 public @NonNull LightsSession openSession() { 102 try { 103 final LightsSession session = new SystemLightsSession(); 104 mService.openSession(session.getToken(), 0); 105 return session; 106 } catch (RemoteException e) { 107 throw e.rethrowFromSystemServer(); 108 } 109 } 110 111 /** 112 * 113 * Creates a new {@link LightsSession} 114 * 115 * @param priority the larger this number, the higher the priority of this session when multiple 116 * light state requests arrive simultaneously. 117 * 118 * @hide 119 */ 120 @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS) 121 @Override openSession(int priority)122 public @NonNull LightsSession openSession(int priority) { 123 try { 124 final LightsSession session = new SystemLightsSession(); 125 mService.openSession(session.getToken(), priority); 126 return session; 127 } catch (RemoteException e) { 128 throw e.rethrowFromSystemServer(); 129 } 130 } 131 132 /** 133 * Encapsulates a session that can be used to control device lights and represents the lifetime 134 * of the requests. 135 */ 136 public final class SystemLightsSession extends LightsManager.LightsSession 137 implements AutoCloseable { 138 139 private final CloseGuard mCloseGuard = new CloseGuard(); 140 private boolean mClosed = false; 141 142 /** 143 * Instantiated by {@link LightsManager#openSession()}. 144 */ 145 @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS) SystemLightsSession()146 private SystemLightsSession() { 147 mCloseGuard.open("SystemLightsSession.close"); 148 } 149 150 /** 151 * Sends a request to modify the states of multiple lights. 152 * 153 * <p>This method only controls lights that aren't overridden by higher-priority sessions. 154 * Additionally, lights not controlled by this session can be controlled by lower-priority 155 * sessions. 156 * 157 * @param request the settings for lights that should change 158 */ 159 @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS) 160 @Override requestLights(@onNull LightsRequest request)161 public void requestLights(@NonNull LightsRequest request) { 162 Preconditions.checkNotNull(request); 163 if (!mClosed) { 164 try { 165 List<Integer> idList = request.getLights(); 166 List<LightState> stateList = request.getLightStates(); 167 int[] ids = new int[idList.size()]; 168 for (int i = 0; i < idList.size(); i++) { 169 ids[i] = idList.get(i); 170 } 171 LightState[] states = new LightState[stateList.size()]; 172 for (int i = 0; i < stateList.size(); i++) { 173 states[i] = stateList.get(i); 174 } 175 mService.setLightStates(getToken(), ids, states); 176 } catch (RemoteException e) { 177 throw e.rethrowFromSystemServer(); 178 } 179 } 180 } 181 182 /** 183 * Closes the session, reverting all changes made through it. 184 */ 185 @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS) 186 @Override close()187 public void close() { 188 if (!mClosed) { 189 try { 190 mService.closeSession(getToken()); 191 mClosed = true; 192 mCloseGuard.close(); 193 } catch (RemoteException e) { 194 throw e.rethrowFromSystemServer(); 195 } 196 } 197 Reference.reachabilityFence(this); 198 } 199 200 /** @hide */ 201 @Override finalize()202 protected void finalize() throws Throwable { 203 try { 204 mCloseGuard.warnIfOpen(); 205 close(); 206 } finally { 207 super.finalize(); 208 } 209 } 210 } 211 } 212