1 /* 2 * Copyright (C) 2008 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 com.android.server.lights; 18 19 import com.android.server.SystemService; 20 import com.android.server.vr.VrManagerService; 21 22 import android.app.ActivityManager; 23 import android.content.Context; 24 import android.os.Handler; 25 import android.os.Message; 26 import android.os.RemoteException; 27 import android.os.Trace; 28 import android.os.UserHandle; 29 import android.provider.Settings; 30 import android.service.vr.IVrManager; 31 import android.service.vr.IVrStateCallbacks; 32 import android.util.Slog; 33 34 public class LightsService extends SystemService { 35 static final String TAG = "LightsService"; 36 static final boolean DEBUG = false; 37 38 final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT]; 39 private boolean mVrModeEnabled; 40 41 private final class LightImpl extends Light { 42 43 private LightImpl(int id) { 44 mId = id; 45 } 46 47 @Override 48 public void setBrightness(int brightness) { 49 setBrightness(brightness, BRIGHTNESS_MODE_USER); 50 } 51 52 @Override 53 public void setBrightness(int brightness, int brightnessMode) { 54 synchronized (this) { 55 int color = brightness & 0x000000ff; 56 color = 0xff000000 | (color << 16) | (color << 8) | color; 57 setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode); 58 } 59 } 60 61 @Override 62 public void setColor(int color) { 63 synchronized (this) { 64 setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0); 65 } 66 } 67 68 @Override 69 public void setFlashing(int color, int mode, int onMS, int offMS) { 70 synchronized (this) { 71 setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER); 72 } 73 } 74 75 @Override 76 public void pulse() { 77 pulse(0x00ffffff, 7); 78 } 79 80 @Override 81 public void pulse(int color, int onMS) { 82 synchronized (this) { 83 if (mBrightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) { 84 return; 85 } 86 if (mColor == 0 && !mFlashing) { 87 setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000, BRIGHTNESS_MODE_USER); 88 mColor = 0; 89 mH.sendMessageDelayed(Message.obtain(mH, 1, this), onMS); 90 } 91 } 92 } 93 94 @Override 95 public void turnOff() { 96 synchronized (this) { 97 setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0); 98 } 99 } 100 101 void enableLowPersistence() { 102 synchronized(this) { 103 setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_LOW_PERSISTENCE); 104 mLocked = true; 105 } 106 } 107 108 void disableLowPersistence() { 109 synchronized(this) { 110 mLocked = false; 111 setLightLocked(mLastColor, LIGHT_FLASH_NONE, 0, 0, mLastBrightnessMode); 112 } 113 } 114 115 private void stopFlashing() { 116 synchronized (this) { 117 setLightLocked(mColor, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_USER); 118 } 119 } 120 121 private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) { 122 if (!mLocked && (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS || 123 mBrightnessMode != brightnessMode)) { 124 if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#" 125 + Integer.toHexString(color) + ": brightnessMode=" + brightnessMode); 126 mLastColor = mColor; 127 mColor = color; 128 mMode = mode; 129 mOnMS = onMS; 130 mOffMS = offMS; 131 mLastBrightnessMode = mBrightnessMode; 132 mBrightnessMode = brightnessMode; 133 Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", 0x" 134 + Integer.toHexString(color) + ")"); 135 try { 136 setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode); 137 } finally { 138 Trace.traceEnd(Trace.TRACE_TAG_POWER); 139 } 140 } 141 } 142 143 private int mId; 144 private int mColor; 145 private int mMode; 146 private int mOnMS; 147 private int mOffMS; 148 private boolean mFlashing; 149 private int mBrightnessMode; 150 private int mLastBrightnessMode; 151 private int mLastColor; 152 private boolean mLocked; 153 } 154 155 public LightsService(Context context) { 156 super(context); 157 158 mNativePointer = init_native(); 159 160 for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) { 161 mLights[i] = new LightImpl(i); 162 } 163 } 164 165 @Override 166 public void onStart() { 167 publishLocalService(LightsManager.class, mService); 168 } 169 170 @Override 171 public void onBootPhase(int phase) { 172 if (phase == PHASE_SYSTEM_SERVICES_READY) { 173 IVrManager vrManager = 174 (IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE); 175 try { 176 vrManager.registerListener(mVrStateCallbacks); 177 } catch (RemoteException e) { 178 Slog.e(TAG, "Failed to register VR mode state listener: " + e); 179 } 180 } 181 } 182 183 private int getVrDisplayMode() { 184 int currentUser = ActivityManager.getCurrentUser(); 185 return Settings.Secure.getIntForUser(getContext().getContentResolver(), 186 Settings.Secure.VR_DISPLAY_MODE, 187 /*default*/Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE, 188 currentUser); 189 } 190 191 private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() { 192 @Override 193 public void onVrStateChanged(boolean enabled) throws RemoteException { 194 LightImpl l = mLights[LightsManager.LIGHT_ID_BACKLIGHT]; 195 int vrDisplayMode = getVrDisplayMode(); 196 197 // User leaves VR mode before altering display settings. 198 if (enabled && vrDisplayMode == Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE) { 199 if (!mVrModeEnabled) { 200 if (DEBUG) 201 Slog.v(TAG, "VR mode enabled, setting brightness to low persistence"); 202 l.enableLowPersistence(); 203 mVrModeEnabled = true; 204 } 205 } else { 206 if (mVrModeEnabled) { 207 if (DEBUG) Slog.v(TAG, "VR mode disabled, resetting brightnes"); 208 l.disableLowPersistence(); 209 mVrModeEnabled = false; 210 } 211 } 212 } 213 }; 214 215 private final LightsManager mService = new LightsManager() { 216 @Override 217 public Light getLight(int id) { 218 if (id < LIGHT_ID_COUNT) { 219 return mLights[id]; 220 } else { 221 return null; 222 } 223 } 224 }; 225 226 @Override 227 protected void finalize() throws Throwable { 228 finalize_native(mNativePointer); 229 super.finalize(); 230 } 231 232 private Handler mH = new Handler() { 233 @Override 234 public void handleMessage(Message msg) { 235 LightImpl light = (LightImpl)msg.obj; 236 light.stopFlashing(); 237 } 238 }; 239 240 private static native long init_native(); 241 private static native void finalize_native(long ptr); 242 243 static native void setLight_native(long ptr, int light, int color, int mode, 244 int onMS, int offMS, int brightnessMode); 245 246 private long mNativePointer; 247 } 248