• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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