android亮度调节在"设置"的"显示"中,分为手动调节和自动调节。其中手动调节就是通过拖动"亮度调节"的拖动条来直接设置亮度值,自动调节则比较复杂,设置自动亮度模式后,再拖动"亮度调节"的拖动条,可以小范围改变亮度值(前提是光照条件不剧烈变化),但这时不是直接设置的亮度值,而是需要通过一系列转变转成亮度值。
现在遇到问题是:在自动亮度调节模式下,调节亮度拖动条到最小,屏幕变得很黑。
设置中的亮度设置是在DisplaySettings.java(/Settings/src/com/android/settings/DisplaySettings.java)
中,但这里面没有拖动条的相关操作,只有设置手动调节和自动调节模式的操作。其实弹出拖动条的操作在BrightnessPreference.java(/Settings/src/com/android/settings/BrightnessPreference.java)
中,它实现了Preference的onClick方法:
protected void onClick() {
Log.i("BrightnessPreference", "BrightnessPreference:brightness dialog open");
getContext().startActivityAsUser(new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG),
UserHandle.CURRENT_OR_SELF);
}
通过查找这个action,发现其就是android.intent.action.SHOW_BRIGHTNESS_DIALOG
,在 SystemUI(frameworks\base\packages\SystemUI)
的AndroidManifest.xml里也出现了:
<activity
android:name=".settings.BrightnessDialog"
android:label="@string/quick_settings_brightness_dialog_title"
android:theme="@android:style/Theme.DeviceDefault.Dialog"
android:finishOnCloseSystemDialogs="true"
android:launchMode="singleInstance"
android:excludeFromRecents="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.SHOW_BRIGHTNESS_DIALOG" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
这里就是通过action启动BrightnessDialog.java(/UsbStorageActivity/src/com/android/systemui/settings/BrightnessDialog.java)
,发现这个Activity就是亮度调节的弹出框,至此就没有Settings什么事了。
-
BrightnessDialog
在BrightnessDialog中初始化拖动条等相关控件,并实例化了
BrightnessController.java(/UsbStorageActivity/src/com/android/systemui/settings/BrightnessController.java)
:setContentView(R.layout.quick_settings_brightness_dialog); final ImageView icon = (ImageView) findViewById(R.id.brightness_icon); final ToggleSlider slider = (ToggleSlider) findViewById(R.id.brightness_slider); mBrightnessController = new BrightnessController(this, icon, slider);
并注册和注销BrightnessController的回调方法:
@Override protected void onStart() { super.onStart(); mBrightnessController.registerCallbacks(); } @Override protected void onStop() { super.onStop(); mBrightnessController.unregisterCallbacks(); }
-
BrightnessController
BrightnessController的回调方法主要是在亮度调节模式改变时更新系统保存的模式,在亮度调节时更新拖动条(此拖动条和下拉栏的亮度条保持一致)。这里主要看亮度设置时的操作。
因为BrightnessController实现了对ToggleSlider的监听,在拖动条改变时设置亮度:@Override public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value) { updateIcon(mAutomatic); if (mExternalChange) return; if (!mAutomatic) { final int val = value + mMinimumBacklight; Log.i(TAG, "brightness mode:"+mAutomatic+"\nvalue:"+value+"value set:"+val); setBrightness(val); if (!tracking) { AsyncTask.execute(new Runnable() { public void run() { Settings.System.putIntForUser(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, val, UserHandle.USER_CURRENT); } }); } } else { final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1; //original code setBrightnessAdj(adj); if (!tracking) { AsyncTask.execute(new Runnable() { public void run() { Settings.System.putFloatForUser(mContext.getContentResolver(), Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adj, UserHandle.USER_CURRENT); } }); } } for (BrightnessStateChangeCallback cb : mChangeCallbacks) { cb.onBrightnessLevelChanged(); } }
value就是拖动条的值,在初始化的时候,亮度条的范围和值都被设置:
private void updateSlider() { if (mAutomatic) { float value = Settings.System.getFloatForUser(mContext.getContentResolver(),Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0, UserHandle.USER_CURRENT); mControl.setMax((int) BRIGHTNESS_ADJ_RESOLUTION); mControl.setValue((int) ((value + 1) * BRIGHTNESS_ADJ_RESOLUTION / 2f)); } else { int value; value = Settings.System.getIntForUser(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, mMaximumBacklight, UserHandle.USER_CURRENT); mControl.setMax(mMaximumBacklight - mMinimumBacklight); mControl.setValue(value - mMinimumBacklight); } }
可以看出自动模式下亮度条最大值为
BRIGHTNESS_ADJ_RESOLUTION
,该值为100,而手动模式下亮度条最大值为mMaximumBacklight - mMinimumBacklight
,其中mMaximumBacklight
为255,mMinimumBacklight
为10。
在拖动条的值改变时,onChange()方法被调用,若为手动模式,则:final int val = value + mMinimumBacklight; setBrightness(val);
可以看出,手动模式直接在从拖动条获取的基数value上加了个亮度的最小值,然后调用
setBrightness(val)
,再来看setBrightness(val)
:private void setBrightness(int brightness) { try { mPower.setTemporaryScreenBrightnessSettingOverride(brightness); } catch (RemoteException ex) { } }
mPower
是IPowerManager的对象,这里先放在一边。
再来看若为自动模式时拖动条改变,final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1; setBrightnessAdj(adj);
其中
BRIGHTNESS_ADJ_RESOLUTION
为100。可以计算出adj的范围随着value的改变始终保持在[-1,1],暂且称之为调节参数。然后调用setBrightnessAdj(adj)
:private void setBrightnessAdj(float adj) { try { mPower.setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(adj); } catch (RemoteException ex) { } }
可以看出,两种模式都最终交给
IPowerManager
处理了,然后基本就是由framework层来进行处理。
3.IPowerManager
IPowerManager开头就有注释:/* * This file is auto-generated. DO NOT MODIFY. * Original file: frameworks/base/core/java/android/os/IPowerManager.aidl */
所以这个文件是aidl自动生成的。
两个方法:@Override public void setTemporaryScreenBrightnessSettingOverride(int brightness) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(brightness); mRemote.transact(Stub.TRANSACTION_setTemporaryScreenBrightnessSettingOverride, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float adj) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeFloat(adj); mRemote.transact(Stub.TRANSACTION_setTemporaryScreenAutoBrightnessAdjustmentSettingOverride, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } }
然后搜索发现在
PowerManagerService.java(com.android.server.power.PowerManagerService.class)
中的BinderService类implements了IPowerManager的Stub类,并且实现了上述两个方法:\/** * Used by the settings application and brightness control widgets to * temporarily override the current screen brightness setting so that the * user can observe the effect of an intended settings change without applying * it immediately. * * The override will be canceled when the setting value is next updated. * * @param brightness The overridden brightness. * * @see android.provider.Settings.System#SCREEN_BRIGHTNESS */ @Override // Binder call public void setTemporaryScreenBrightnessSettingOverride(int brightness) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); final long ident = Binder.clearCallingIdentity(); try { setTemporaryScreenBrightnessSettingOverrideInternal(brightness); } finally { Binder.restoreCallingIdentity(ident); } } /** * Used by the settings application and brightness control widgets to * temporarily override the current screen auto-brightness adjustment setting so that the * user can observe the effect of an intended settings change without applying * it immediately. * * The override will be canceled when the setting value is next updated. * * @param adj The overridden brightness, or Float.NaN to disable the override. * * @see android.provider.Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ */ @Override // Binder call public void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float adj) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); final long ident = Binder.clearCallingIdentity(); try { setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(adj); } finally { Binder.restoreCallingIdentity(ident); } }
注释里说明,这两个方法是Settings和亮度调节插件使用的,再来看值传进来后调用的两个方法:
private void setTemporaryScreenBrightnessSettingOverrideInternal(int brightness) { synchronized (mLock) { if (mTemporaryScreenBrightnessSettingOverride != brightness) { mTemporaryScreenBrightnessSettingOverride = brightness; mDirty |= DIRTY_SETTINGS; updatePowerStateLocked(); } } } private void setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(float adj) { synchronized (mLock) { // Note: This condition handles NaN because NaN is not equal to any other // value, including itself. if (mTemporaryScreenAutoBrightnessAdjustmentSettingOverride != adj) { mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = adj; mDirty |= DIRTY_SETTINGS; updatePowerStateLocked(); } } }
拿到值后赋值给一个全局变量,然后马上调用
updatePowerStateLocked()
,再来看此方法对传入的值做了哪些操作:/** * Updates the display power state asynchronously. * When the update is finished, mDisplayReady will be set to true. The display * controller posts a message to tell us when the actual display power state * has been updated so we come back here to double-check and finish up. * * This function recalculates the display power state each time. * * @return True if the display became ready. */ private boolean updateDisplayPowerStateLocked(int dirty) { final boolean oldDisplayReady = mDisplayReady; if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST)) != 0) { mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked(); // Determine appropriate screen brightness and auto-brightness adjustments. int screenBrightness = mScreenBrightnessSettingDefault; float screenAutoBrightnessAdjustment = 0.0f; boolean autoBrightness = (mScreenBrightnessModeSetting == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) { screenBrightness = mScreenBrightnessOverrideFromWindowManager; autoBrightness = false; } else if (isValidBrightness(mTemporaryScreenBrightnessSettingOverride)) { screenBrightness = mTemporaryScreenBrightnessSettingOverride; } else if (isValidBrightness(mScreenBrightnessSetting)) { screenBrightness = mScreenBrightnessSetting; } if (autoBrightness) { screenBrightness = mScreenBrightnessSettingDefault; if (isValidAutoBrightnessAdjustment( mTemporaryScreenAutoBrightnessAdjustmentSettingOverride)) { screenAutoBrightnessAdjustment = mTemporaryScreenAutoBrightnessAdjustmentSettingOverride; } else if (isValidAutoBrightnessAdjustment( mScreenAutoBrightnessAdjustmentSetting)) { screenAutoBrightnessAdjustment = mScreenAutoBrightnessAdjustmentSetting; } } screenBrightness = Math.max(Math.min(screenBrightness, mScreenBrightnessSettingMaximum), mScreenBrightnessSettingMinimum); screenAutoBrightnessAdjustment = Math.max(Math.min( screenAutoBrightnessAdjustment, 1.0f), -1.0f); // Update display power request. mDisplayPowerRequest.screenBrightness = screenBrightness; mDisplayPowerRequest.screenAutoBrightnessAdjustment = screenAutoBrightnessAdjustment; mDisplayPowerRequest.useAutoBrightness = autoBrightness; mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked(); mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled; mDisplayPowerRequest.boostScreenBrightness = mScreenBrightnessBoostInProgress; if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) { mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager; mDisplayPowerRequest.dozeScreenBrightness = mDozeScreenBrightnessOverrideFromDreamManager; } else { mDisplayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN; mDisplayPowerRequest.dozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT; } mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest, mRequestWaitForNegativeProximity); mRequestWaitForNegativeProximity = false; if (DEBUG_SPEW) { Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady + ", policy=" + mDisplayPowerRequest.policy + ", mWakefulness=" + mWakefulness + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary) + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary) + ", mBootCompleted=" + mBootCompleted + ", mScreenBrightnessBoostInProgress=" + mScreenBrightnessBoostInProgress); } } return mDisplayReady && !oldDisplayReady; }
发现最终值都被赋给
mDisplayPowerRequest
的属性,然后调用mDisplayManagerInternal.requestPowerState
将值传出返回结果。mDisplayManagerInternal
是DisplayManagerInternal(android.hardware.display.DisplayManagerInternal.class)
的对象,再来看看DisplayManagerInternal
:
4.DisplayManagerInternalpublic abstract boolean requestPowerState(DisplayPowerRequest request, boolean waitForNegativeProximity);
发现并没有具体的实现方法。通过搜索发现
DisplayManageService(com.android.server.display.DisplayManagerService.class)
中的LocalService
类继承了DisplayManagerInternal
并实现了requestPowerState()
方法:@Override public boolean requestPowerState(DisplayPowerRequest request, boolean waitForNegativeProximity) { return mDisplayPowerController.requestPowerState(request, waitForNegativeProximity); }
发现调用了
DisplayPowerController(com.android.server.display.DisplayPowerController.class)
的requestPowerState()
方法作为返回结果。
5.DisplayPowerControllerpublic boolean requestPowerState(DisplayPowerRequest request, boolean waitForNegativeProximity) { if (DEBUG) { Slog.d(TAG, "requestPowerState: " + request + ", waitForNegativeProximity=" + waitForNegativeProximity); } synchronized (mLock) { boolean changed = false; if (waitForNegativeProximity && !mPendingWaitForNegativeProximityLocked) { mPendingWaitForNegativeProximityLocked = true; changed = true; } if (mPendingRequestLocked == null) { mPendingRequestLocked = new DisplayPowerRequest(request); changed = true; } else if (!mPendingRequestLocked.equals(request)) { mPendingRequestLocked.copyFrom(request); changed = true; } if (changed) { mDisplayReadyLocked = false; } if (changed && !mPendingRequestChangedLocked) { mPendingRequestChangedLocked = true; sendUpdatePowerStateLocked(); } return mDisplayReadyLocked; } }
可以看出,先是将request对象赋给本地,然后调用
sendUpdatePowerStateLocked()
:private void sendUpdatePowerStateLocked() { if (!mPendingUpdatePowerStateLocked) { mPendingUpdatePowerStateLocked = true; Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE); msg.setAsynchronous(true); mHandler.sendMessage(msg); } }
交给handler处理:
case MSG_UPDATE_POWER_STATE: updatePowerState(); break;
调用
updatePowerState()
方法,其中有这样一段代码:// Configure auto-brightness. boolean autoBrightnessEnabled = false; if (mAutomaticBrightnessController != null) { final boolean autoBrightnessEnabledInDoze = mAllowAutoBrightnessWhileDozingConfig && (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND); autoBrightnessEnabled = mPowerRequest.useAutoBrightness && (state == Display.STATE_ON || autoBrightnessEnabledInDoze) && brightness < 0; mAutomaticBrightnessController.configure(autoBrightnessEnabled, mPowerRequest.screenAutoBrightnessAdjustment, state != Display.STATE_ON); }
mAutomaticBrightnessController
是AutomaticBrightnessController(com.android.server.display.AutomaticBrightnessController.class)
对象,下面来看AutomaticBrightnessController
.
6.AutomaticBrightnessControllerpublic void configure(boolean enable, float adjustment, boolean dozing) { // While dozing, the application processor may be suspended which will prevent us from // receiving new information from the light sensor. On some devices, we may be able to // switch to a wake-up light sensor instead but for now we will simply disable the sensor // and hold onto the last computed screen auto brightness. We save the dozing flag for // debugging purposes. mDozing = dozing; boolean changed = setLightSensorEnabled(enable && !dozing); changed |= setScreenAutoBrightnessAdjustment(adjustment); if (changed) { updateAutoBrightness(false /*sendUpdate*/); } }
private boolean setScreenAutoBrightnessAdjustment(float adjustment) { if (adjustment != mScreenAutoBrightnessAdjustment) { mScreenAutoBrightnessAdjustment = adjustment; return true; } return false; }
拿到亮度调节参数后:
private void updateAutoBrightness(boolean sendUpdate) { if (!mAmbientLuxValid) { return; } float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux); float gamma = 1.0f; if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT && mScreenAutoBrightnessAdjustment != 0.0f) { final float adjGamma = MathUtils.pow(SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA, Math.min(1.0f, Math.max(-1.0f, -mScreenAutoBrightnessAdjustment))); gamma *= adjGamma; if (DEBUG) { Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma); } } if (USE_TWILIGHT_ADJUSTMENT) { TwilightState state = mTwilight.getCurrentState(); if (state != null && state.isNight()) { final long now = System.currentTimeMillis(); final float earlyGamma = getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise()); final float lateGamma = getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise()); gamma *= earlyGamma * lateGamma; if (DEBUG) { Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma + ", lateGamma=" + lateGamma); } } } if (gamma != 1.0f) { final float in = value; value = MathUtils.pow(value, gamma); if (DEBUG) { Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma + ", in=" + in + ", out=" + value); } } int newScreenAutoBrightness = clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON)); if (mScreenAutoBrightness != newScreenAutoBrightness) { if (DEBUG) { Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness=" + mScreenAutoBrightness + ", newScreenAutoBrightness=" + newScreenAutoBrightness); } mScreenAutoBrightness = newScreenAutoBrightness; mLastScreenAutoBrightnessGamma = gamma; if (sendUpdate) { mCallbacks.updateBrightness(); } } }
这里是一大段针对自动亮度调节,将亮度调节系数和一段时间内的光线感应器获取的光强的加权平均通过一系列运算转化为合适的屏幕背光亮度,具体的转化模型这里不深究。
在这里来看一下,每次转化好亮度后都会做如下处理:
private int clampScreenBrightness(int value) {
return MathUtils.constrain(value,
mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
}
mScreenBrightnessRangeMinimum
就是最小值,由构造函数传过来,发现是DisplayPowerController
实例化AutomaticBrightnessController
时传入的:
mAutomaticBrightnessController = new AutomaticBrightnessController(this,
handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
mScreenBrightnessRangeMaximum, dozeScaleFactor);
在DisplayPowerController
的构造函数中:
int screenBrightnessRangeMinimum = Math.min(Math.min(
screenBrightnessSettingMinimum, mScreenBrightnessDimConfig),
mScreenBrightnessDarkConfig);
这三个值均取自config.xml(frameworks\base\core\res\res\values\config.xml)
分别为:
screenBrightnessSettingMinimum:config_screenBrightnessSettingMinimum
mScreenBrightnessDimConfig:config_screenBrightnessDim
mScreenBrightnessDarkConfig:config_screenBrightnessDark
发现config.xml文件中三个值最小的为1,改为10之后问题解决。