1 /* * Copyright (C) 2008 The Android Open Source Project 2 * 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 16 package com.android.server.lights; 17 18 import android.app.ActivityManager; 19 import android.content.Context; 20 import android.os.Handler; 21 import android.os.IBinder; 22 import android.os.Message; 23 import android.os.PowerManager; 24 import android.os.Trace; 25 import android.provider.Settings; 26 import android.util.Slog; 27 import android.view.SurfaceControl; 28 29 import com.android.server.SystemService; 30 31 public class LightsService extends SystemService { 32 static final String TAG = "LightsService"; 33 static final boolean DEBUG = false; 34 35 final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT]; 36 37 private final class LightImpl extends Light { 38 39 private final IBinder mDisplayToken; 40 private final int mSurfaceControlMaximumBrightness; 41 LightImpl(Context context, int id)42 private LightImpl(Context context, int id) { 43 mId = id; 44 mDisplayToken = SurfaceControl.getInternalDisplayToken(); 45 final boolean brightnessSupport = SurfaceControl.getDisplayBrightnessSupport( 46 mDisplayToken); 47 if (DEBUG) { 48 Slog.d(TAG, "Display brightness support: " + brightnessSupport); 49 } 50 int maximumBrightness = 0; 51 if (brightnessSupport) { 52 PowerManager pm = context.getSystemService(PowerManager.class); 53 if (pm != null) { 54 maximumBrightness = pm.getMaximumScreenBrightnessSetting(); 55 } 56 } 57 mSurfaceControlMaximumBrightness = maximumBrightness; 58 } 59 60 @Override setBrightness(int brightness)61 public void setBrightness(int brightness) { 62 setBrightness(brightness, BRIGHTNESS_MODE_USER); 63 } 64 65 @Override setBrightness(int brightness, int brightnessMode)66 public void setBrightness(int brightness, int brightnessMode) { 67 synchronized (this) { 68 // LOW_PERSISTENCE cannot be manually set 69 if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) { 70 Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mId + 71 ": brightness=0x" + Integer.toHexString(brightness)); 72 return; 73 } 74 // Ideally, we'd like to set the brightness mode through the SF/HWC as well, but 75 // right now we just fall back to the old path through Lights brightessMode is 76 // anything but USER or the device shouldBeInLowPersistenceMode(). 77 if (brightnessMode == BRIGHTNESS_MODE_USER && !shouldBeInLowPersistenceMode() 78 && mSurfaceControlMaximumBrightness == 255) { 79 // TODO: the last check should be mSurfaceControlMaximumBrightness != 0; the 80 // reason we enforce 255 right now is to stay consistent with the old path. In 81 // the future, the framework should be refactored so that brightness is a float 82 // between 0.0f and 1.0f, and the actual number of supported brightness levels 83 // is determined in the device-specific implementation. 84 if (DEBUG) { 85 Slog.d(TAG, "Using new setBrightness path!"); 86 } 87 SurfaceControl.setDisplayBrightness(mDisplayToken, 88 (float) brightness / mSurfaceControlMaximumBrightness); 89 } else { 90 int color = brightness & 0x000000ff; 91 color = 0xff000000 | (color << 16) | (color << 8) | color; 92 setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode); 93 } 94 } 95 } 96 97 @Override setColor(int color)98 public void setColor(int color) { 99 synchronized (this) { 100 setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0); 101 } 102 } 103 104 @Override setFlashing(int color, int mode, int onMS, int offMS)105 public void setFlashing(int color, int mode, int onMS, int offMS) { 106 synchronized (this) { 107 setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER); 108 } 109 } 110 111 @Override pulse()112 public void pulse() { 113 pulse(0x00ffffff, 7); 114 } 115 116 @Override pulse(int color, int onMS)117 public void pulse(int color, int onMS) { 118 synchronized (this) { 119 if (mColor == 0 && !mFlashing) { 120 setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000, 121 BRIGHTNESS_MODE_USER); 122 mColor = 0; 123 mH.sendMessageDelayed(Message.obtain(mH, 1, this), onMS); 124 } 125 } 126 } 127 128 @Override turnOff()129 public void turnOff() { 130 synchronized (this) { 131 setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0); 132 } 133 } 134 135 @Override setVrMode(boolean enabled)136 public void setVrMode(boolean enabled) { 137 synchronized (this) { 138 if (mVrModeEnabled != enabled) { 139 mVrModeEnabled = enabled; 140 141 mUseLowPersistenceForVR = 142 (getVrDisplayMode() == Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE); 143 if (shouldBeInLowPersistenceMode()) { 144 mLastBrightnessMode = mBrightnessMode; 145 } 146 147 // NOTE: We do not trigger a call to setLightLocked here. We do not know the 148 // current brightness or other values when leaving VR so we avoid any incorrect 149 // jumps. The code that calls this method will immediately issue a brightness 150 // update which is when the change will occur. 151 } 152 } 153 } 154 stopFlashing()155 private void stopFlashing() { 156 synchronized (this) { 157 setLightLocked(mColor, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_USER); 158 } 159 } 160 setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode)161 private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) { 162 if (shouldBeInLowPersistenceMode()) { 163 brightnessMode = BRIGHTNESS_MODE_LOW_PERSISTENCE; 164 } else if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) { 165 brightnessMode = mLastBrightnessMode; 166 } 167 168 if (!mInitialized || color != mColor || mode != mMode || onMS != mOnMS || 169 offMS != mOffMS || mBrightnessMode != brightnessMode) { 170 if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#" 171 + Integer.toHexString(color) + ": brightnessMode=" + brightnessMode); 172 mInitialized = true; 173 mLastColor = mColor; 174 mColor = color; 175 mMode = mode; 176 mOnMS = onMS; 177 mOffMS = offMS; 178 mBrightnessMode = brightnessMode; 179 Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", 0x" 180 + Integer.toHexString(color) + ")"); 181 try { 182 setLight_native(mId, color, mode, onMS, offMS, brightnessMode); 183 } finally { 184 Trace.traceEnd(Trace.TRACE_TAG_POWER); 185 } 186 } 187 } 188 shouldBeInLowPersistenceMode()189 private boolean shouldBeInLowPersistenceMode() { 190 return mVrModeEnabled && mUseLowPersistenceForVR; 191 } 192 193 private int mId; 194 private int mColor; 195 private int mMode; 196 private int mOnMS; 197 private int mOffMS; 198 private boolean mFlashing; 199 private int mBrightnessMode; 200 private int mLastBrightnessMode; 201 private int mLastColor; 202 private boolean mVrModeEnabled; 203 private boolean mUseLowPersistenceForVR; 204 private boolean mInitialized; 205 } 206 LightsService(Context context)207 public LightsService(Context context) { 208 super(context); 209 210 for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) { 211 mLights[i] = new LightImpl(context, i); 212 } 213 } 214 215 @Override onStart()216 public void onStart() { 217 publishLocalService(LightsManager.class, mService); 218 } 219 220 @Override onBootPhase(int phase)221 public void onBootPhase(int phase) { 222 } 223 getVrDisplayMode()224 private int getVrDisplayMode() { 225 int currentUser = ActivityManager.getCurrentUser(); 226 return Settings.Secure.getIntForUser(getContext().getContentResolver(), 227 Settings.Secure.VR_DISPLAY_MODE, 228 /*default*/Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE, 229 currentUser); 230 } 231 232 private final LightsManager mService = new LightsManager() { 233 @Override 234 public Light getLight(int id) { 235 if (0 <= id && id < LIGHT_ID_COUNT) { 236 return mLights[id]; 237 } else { 238 return null; 239 } 240 } 241 }; 242 243 private Handler mH = new Handler() { 244 @Override 245 public void handleMessage(Message msg) { 246 LightImpl light = (LightImpl)msg.obj; 247 light.stopFlashing(); 248 } 249 }; 250 setLight_native(int light, int color, int mode, int onMS, int offMS, int brightnessMode)251 static native void setLight_native(int light, int color, int mode, 252 int onMS, int offMS, int brightnessMode); 253 } 254