1 /* 2 * Copyright (C) 2016 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.car.systeminterface; 18 19 import static com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MAX; 20 import static com.android.settingslib.display.BrightnessUtils.convertGammaToLinear; 21 import static com.android.settingslib.display.BrightnessUtils.convertLinearToGamma; 22 23 import android.app.ActivityManager; 24 import android.content.BroadcastReceiver; 25 import android.content.ContentResolver; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.database.ContentObserver; 30 import android.hardware.display.DisplayManager; 31 import android.hardware.display.DisplayManager.DisplayListener; 32 import android.hardware.input.InputManager; 33 import android.os.Handler; 34 import android.os.Looper; 35 import android.os.PowerManager; 36 import android.os.SystemClock; 37 import android.os.UserHandle; 38 import android.provider.Settings.SettingNotFoundException; 39 import android.provider.Settings.System; 40 import android.util.Slog; 41 import android.view.Display; 42 import android.view.InputDevice; 43 44 import com.android.car.CarLog; 45 import com.android.car.power.CarPowerManagementService; 46 import com.android.internal.annotations.GuardedBy; 47 48 /** 49 * Interface that abstracts display operations 50 */ 51 public interface DisplayInterface { 52 /** 53 * Sets display brightness. 54 * 55 * @param brightness Level from 0 to 100% 56 */ setDisplayBrightness(int brightness)57 void setDisplayBrightness(int brightness); 58 59 /** 60 * Turns on or off display. 61 * 62 * @param on {@code true} to turn on, {@code false} to turn off. 63 */ setDisplayState(boolean on)64 void setDisplayState(boolean on); 65 66 /** 67 * Starts monitoring the display state change. 68 * 69 * <p> When there is a change, {@link CarPowerManagementService} is notified. 70 * 71 * @param service {@link CarPowerManagementService} to listen to the change. 72 */ startDisplayStateMonitoring(CarPowerManagementService service)73 void startDisplayStateMonitoring(CarPowerManagementService service); 74 75 /** 76 * Stops monitoring the display state change. 77 */ stopDisplayStateMonitoring()78 void stopDisplayStateMonitoring(); 79 80 /** 81 * Gets the current on/off state of display. 82 */ isDisplayEnabled()83 boolean isDisplayEnabled(); 84 85 /** 86 * Refreshing display brightness. Used when user is switching and car turned on. 87 */ refreshDisplayBrightness()88 void refreshDisplayBrightness(); 89 90 /** 91 * Default implementation of display operations 92 */ 93 class DefaultImpl implements DisplayInterface { 94 private final ActivityManager mActivityManager; 95 private final ContentResolver mContentResolver; 96 private final Context mContext; 97 private final DisplayManager mDisplayManager; 98 private final InputManager mInputManager; 99 private final Object mLock = new Object(); 100 private final int mMaximumBacklight; 101 private final int mMinimumBacklight; 102 private final PowerManager mPowerManager; 103 private final WakeLockInterface mWakeLockInterface; 104 @GuardedBy("mLock") 105 private CarPowerManagementService mService; 106 @GuardedBy("mLock") 107 private boolean mDisplayStateSet; 108 @GuardedBy("mLock") 109 private int mLastBrightnessLevel = -1; 110 111 private final ContentObserver mBrightnessObserver = 112 new ContentObserver(new Handler(Looper.getMainLooper())) { 113 @Override 114 public void onChange(boolean selfChange) { 115 refreshDisplayBrightness(); 116 } 117 }; 118 119 private final DisplayManager.DisplayListener mDisplayListener = new DisplayListener() { 120 @Override 121 public void onDisplayAdded(int displayId) { 122 //ignore 123 } 124 125 @Override 126 public void onDisplayRemoved(int displayId) { 127 //ignore 128 } 129 130 @Override 131 public void onDisplayChanged(int displayId) { 132 if (displayId == Display.DEFAULT_DISPLAY) { 133 handleMainDisplayChanged(); 134 } 135 } 136 }; 137 138 private final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() { 139 @Override 140 public void onReceive(Context context, Intent intent) { 141 onUsersUpdate(); 142 } 143 }; 144 DefaultImpl(Context context, WakeLockInterface wakeLockInterface)145 DefaultImpl(Context context, WakeLockInterface wakeLockInterface) { 146 mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 147 mContext = context; 148 mContentResolver = mContext.getContentResolver(); 149 mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); 150 mInputManager = (InputManager) mContext.getSystemService(Context.INPUT_SERVICE); 151 mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 152 mMaximumBacklight = mPowerManager.getMaximumScreenBrightnessSetting(); 153 mMinimumBacklight = mPowerManager.getMinimumScreenBrightnessSetting(); 154 mWakeLockInterface = wakeLockInterface; 155 156 mContext.registerReceiverAsUser( 157 mUserChangeReceiver, 158 UserHandle.ALL, 159 new IntentFilter(Intent.ACTION_USER_SWITCHED), 160 null, 161 null); 162 } 163 164 @Override refreshDisplayBrightness()165 public void refreshDisplayBrightness() { 166 synchronized (mLock) { 167 if (mService == null) { 168 Slog.e(CarLog.TAG_POWER, 169 "Could not set brightness: no CarPowerManagementService"); 170 return; 171 } 172 int gamma = GAMMA_SPACE_MAX; 173 try { 174 int linear = System.getIntForUser( 175 mContentResolver, 176 System.SCREEN_BRIGHTNESS, 177 ActivityManager.getCurrentUser()); 178 gamma = convertLinearToGamma(linear, mMinimumBacklight, mMaximumBacklight); 179 } catch (SettingNotFoundException e) { 180 Slog.e(CarLog.TAG_POWER, "Could not get SCREEN_BRIGHTNESS: ", e); 181 } 182 int percentBright = (gamma * 100 + ((GAMMA_SPACE_MAX + 1) / 2)) / GAMMA_SPACE_MAX; 183 mService.sendDisplayBrightness(percentBright); 184 } 185 } 186 handleMainDisplayChanged()187 private void handleMainDisplayChanged() { 188 boolean isOn = isMainDisplayOn(); 189 CarPowerManagementService service; 190 synchronized (mLock) { 191 if (mDisplayStateSet == isOn) { // same as what is set 192 return; 193 } 194 service = mService; 195 } 196 service.handleMainDisplayChanged(isOn); 197 } 198 isMainDisplayOn()199 private boolean isMainDisplayOn() { 200 Display disp = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); 201 return disp.getState() == Display.STATE_ON; 202 } 203 204 @Override setDisplayBrightness(int percentBright)205 public void setDisplayBrightness(int percentBright) { 206 synchronized (mLock) { 207 if (percentBright == mLastBrightnessLevel) { 208 // We have already set the value last time. Skipping 209 return; 210 } 211 mLastBrightnessLevel = percentBright; 212 } 213 int gamma = (percentBright * GAMMA_SPACE_MAX + 50) / 100; 214 int linear = convertGammaToLinear(gamma, mMinimumBacklight, mMaximumBacklight); 215 System.putIntForUser( 216 mContentResolver, 217 System.SCREEN_BRIGHTNESS, 218 linear, 219 ActivityManager.getCurrentUser()); 220 } 221 222 @Override startDisplayStateMonitoring(CarPowerManagementService service)223 public void startDisplayStateMonitoring(CarPowerManagementService service) { 224 synchronized (mLock) { 225 mService = service; 226 mDisplayStateSet = isMainDisplayOn(); 227 } 228 mContentResolver.registerContentObserver( 229 System.getUriFor(System.SCREEN_BRIGHTNESS), 230 false, 231 mBrightnessObserver, 232 UserHandle.USER_ALL); 233 mDisplayManager.registerDisplayListener(mDisplayListener, service.getHandler()); 234 refreshDisplayBrightness(); 235 } 236 237 @Override stopDisplayStateMonitoring()238 public void stopDisplayStateMonitoring() { 239 mDisplayManager.unregisterDisplayListener(mDisplayListener); 240 mContentResolver.unregisterContentObserver(mBrightnessObserver); 241 } 242 243 @Override setDisplayState(boolean on)244 public void setDisplayState(boolean on) { 245 synchronized (mLock) { 246 mDisplayStateSet = on; 247 } 248 if (on) { 249 mWakeLockInterface.switchToFullWakeLock(); 250 Slog.i(CarLog.TAG_POWER, "on display"); 251 mPowerManager.wakeUp(SystemClock.uptimeMillis()); 252 } else { 253 mWakeLockInterface.switchToPartialWakeLock(); 254 Slog.i(CarLog.TAG_POWER, "off display"); 255 mPowerManager.goToSleep(SystemClock.uptimeMillis()); 256 } 257 // Turn touchscreen input devices on or off, the same as the display 258 for (int deviceId : mInputManager.getInputDeviceIds()) { 259 InputDevice inputDevice = mInputManager.getInputDevice(deviceId); 260 if (inputDevice != null 261 && (inputDevice.getSources() & InputDevice.SOURCE_TOUCHSCREEN) 262 == InputDevice.SOURCE_TOUCHSCREEN) { 263 if (on) { 264 mInputManager.enableInputDevice(deviceId); 265 } else { 266 mInputManager.disableInputDevice(deviceId); 267 } 268 } 269 } 270 } 271 272 @Override isDisplayEnabled()273 public boolean isDisplayEnabled() { 274 return isMainDisplayOn(); 275 } 276 onUsersUpdate()277 private void onUsersUpdate() { 278 synchronized (mLock) { 279 if (mService == null) { 280 // CarPowerManagementService is not connected yet 281 return; 282 } 283 // We need to reset last value 284 mLastBrightnessLevel = -1; 285 } 286 refreshDisplayBrightness(); 287 } 288 } 289 } 290