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