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.car.userlib.CarUserManagerHelper; 25 import android.car.userlib.CarUserManagerHelper.OnUsersUpdateListener; 26 import android.content.ContentResolver; 27 import android.content.Context; 28 import android.database.ContentObserver; 29 import android.hardware.display.DisplayManager; 30 import android.hardware.display.DisplayManager.DisplayListener; 31 import android.os.Handler; 32 import android.os.Looper; 33 import android.os.PowerManager; 34 import android.os.RemoteException; 35 import android.os.ServiceManager; 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.DisplayAddress; 43 import android.view.IWindowManager; 44 45 import com.android.car.CarLog; 46 import com.android.car.CarPowerManagementService; 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 * Reconfigure all secondary displays due to b/131909551 67 */ reconfigureSecondaryDisplays()68 void reconfigureSecondaryDisplays(); 69 /** 70 * Default implementation of display operations 71 */ 72 class DefaultImpl implements DisplayInterface, OnUsersUpdateListener { 73 static final String TAG = DisplayInterface.class.getSimpleName(); 74 75 private final ActivityManager mActivityManager; 76 private final ContentResolver mContentResolver; 77 private final Context mContext; 78 private final DisplayManager mDisplayManager; 79 private final int mMaximumBacklight; 80 private final int mMinimumBacklight; 81 private final PowerManager mPowerManager; 82 private final WakeLockInterface mWakeLockInterface; 83 private CarPowerManagementService mService; 84 private boolean mDisplayStateSet; 85 private CarUserManagerHelper mCarUserManagerHelper; 86 private int mLastBrightnessLevel = -1; 87 88 private ContentObserver mBrightnessObserver = 89 new ContentObserver(new Handler(Looper.getMainLooper())) { 90 @Override 91 public void onChange(boolean selfChange) { 92 refreshDisplayBrightness(); 93 } 94 }; 95 96 private final DisplayManager.DisplayListener mDisplayListener = new DisplayListener() { 97 @Override 98 public void onDisplayAdded(int displayId) { 99 //ignore 100 } 101 102 @Override 103 public void onDisplayRemoved(int displayId) { 104 //ignore 105 } 106 107 @Override 108 public void onDisplayChanged(int displayId) { 109 if (displayId == Display.DEFAULT_DISPLAY) { 110 handleMainDisplayChanged(); 111 } 112 } 113 }; 114 DefaultImpl(Context context, WakeLockInterface wakeLockInterface)115 DefaultImpl(Context context, WakeLockInterface wakeLockInterface) { 116 mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 117 mContext = context; 118 mContentResolver = mContext.getContentResolver(); 119 mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); 120 mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 121 mMaximumBacklight = mPowerManager.getMaximumScreenBrightnessSetting(); 122 mMinimumBacklight = mPowerManager.getMinimumScreenBrightnessSetting(); 123 mWakeLockInterface = wakeLockInterface; 124 mCarUserManagerHelper = new CarUserManagerHelper(context); 125 mCarUserManagerHelper.registerOnUsersUpdateListener(this); 126 } 127 128 @Override refreshDisplayBrightness()129 public synchronized void refreshDisplayBrightness() { 130 int gamma = GAMMA_SPACE_MAX; 131 try { 132 int linear = System.getIntForUser( 133 mContentResolver, 134 System.SCREEN_BRIGHTNESS, 135 mActivityManager.getCurrentUser()); 136 gamma = convertLinearToGamma(linear, mMinimumBacklight, mMaximumBacklight); 137 } catch (SettingNotFoundException e) { 138 Log.e(CarLog.TAG_POWER, "Could not get SCREEN_BRIGHTNESS: " + e); 139 } 140 int percentBright = (gamma * 100 + ((GAMMA_SPACE_MAX + 1) / 2)) / GAMMA_SPACE_MAX; 141 mService.sendDisplayBrightness(percentBright); 142 } 143 handleMainDisplayChanged()144 private void handleMainDisplayChanged() { 145 boolean isOn = isMainDisplayOn(); 146 CarPowerManagementService service; 147 synchronized (this) { 148 if (mDisplayStateSet == isOn) { // same as what is set 149 return; 150 } 151 service = mService; 152 } 153 service.handleMainDisplayChanged(isOn); 154 } 155 isMainDisplayOn()156 private boolean isMainDisplayOn() { 157 Display disp = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); 158 return disp.getState() == Display.STATE_ON; 159 } 160 161 @Override setDisplayBrightness(int percentBright)162 public void setDisplayBrightness(int percentBright) { 163 if (percentBright == mLastBrightnessLevel) { 164 // We have already set the value last time. Skipping 165 return; 166 } 167 mLastBrightnessLevel = percentBright; 168 int gamma = (percentBright * GAMMA_SPACE_MAX + 50) / 100; 169 int linear = convertGammaToLinear(gamma, mMinimumBacklight, mMaximumBacklight); 170 System.putIntForUser( 171 mContentResolver, 172 System.SCREEN_BRIGHTNESS, 173 linear, 174 mActivityManager.getCurrentUser()); 175 } 176 177 @Override startDisplayStateMonitoring(CarPowerManagementService service)178 public void startDisplayStateMonitoring(CarPowerManagementService service) { 179 synchronized (this) { 180 mService = service; 181 mDisplayStateSet = isMainDisplayOn(); 182 } 183 mContentResolver.registerContentObserver( 184 System.getUriFor(System.SCREEN_BRIGHTNESS), 185 false, 186 mBrightnessObserver, 187 UserHandle.USER_ALL); 188 mDisplayManager.registerDisplayListener(mDisplayListener, service.getHandler()); 189 refreshDisplayBrightness(); 190 } 191 192 @Override stopDisplayStateMonitoring()193 public void stopDisplayStateMonitoring() { 194 mDisplayManager.unregisterDisplayListener(mDisplayListener); 195 mContentResolver.unregisterContentObserver(mBrightnessObserver); 196 } 197 198 @Override setDisplayState(boolean on)199 public void setDisplayState(boolean on) { 200 synchronized (this) { 201 mDisplayStateSet = on; 202 } 203 if (on) { 204 mWakeLockInterface.switchToFullWakeLock(); 205 Log.i(CarLog.TAG_POWER, "on display"); 206 mPowerManager.wakeUp(SystemClock.uptimeMillis()); 207 } else { 208 mWakeLockInterface.switchToPartialWakeLock(); 209 Log.i(CarLog.TAG_POWER, "off display"); 210 mPowerManager.goToSleep(SystemClock.uptimeMillis()); 211 } 212 } 213 214 @Override onUsersUpdate()215 public void onUsersUpdate() { 216 if (mService == null) { 217 // CarPowerManagementService is not connected yet 218 return; 219 } 220 // We need to reset last value 221 mLastBrightnessLevel = -1; 222 refreshDisplayBrightness(); 223 } 224 225 @Override reconfigureSecondaryDisplays()226 public void reconfigureSecondaryDisplays() { 227 IWindowManager wm = IWindowManager.Stub 228 .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)); 229 if (wm == null) { 230 Log.e(TAG, "reconfigureSecondaryDisplays IWindowManager not available"); 231 return; 232 } 233 Display[] displays = mDisplayManager.getDisplays(); 234 for (Display display : displays) { 235 if (display.getDisplayId() == Display.DEFAULT_DISPLAY) { // skip main 236 continue; 237 } 238 // Only use physical secondary displays 239 if (display.getAddress() instanceof DisplayAddress.Physical) { 240 int displayId = display.getDisplayId(); 241 try { 242 // Do not change the mode but this triggers reconfiguring. 243 int windowingMode = wm.getWindowingMode(displayId); 244 wm.setWindowingMode(displayId, windowingMode); 245 } catch (RemoteException e) { 246 Log.e(CarLog.TAG_SERVICE, "cannot access IWindowManager", e); 247 } 248 } 249 } 250 } 251 } 252 } 253