本文主要讲述android5.1系统对背光的处理,从初始化到点击自动背光模式再到UI的同步处理,文章分为三点讲述:
1.背光的初始化
2.自动背光的调用过程:从点击setting中自动调节亮度开始
3.systemUI和setting对背光模式的同步
大部分的服务的起点都在systemserver,背光的服务也不例外。首先启动一些基础的服务:
private void run() {
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Start services.
try {
startOtherServices();
}
}
创建SystemServiceManager,并将该对象放入一个静态类LocalServices中,这样在systemserver进程中可以直接调用各种静态类中的服务了。在startOtherService中会调用startBootsstrapService方法:
private void startBootstrapServices() {
// Display manager is needed to provide display metrics before package manager
// starts up.
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
}
进入mSystemServiceManager.startService中,
public T startService(Class serviceClass) {
final String name = serviceClass.getName();
// 创建该服务,创建的服务都是SystemService的子类,需要实现onStart方法。
final T service;
try {
Constructor constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
}
// 注册服务,将该服务放到一个列表
mServices.add(service);
// 调用SystemService子类的onStart方法,在该方法中去注册服务到servermanager中
try {
service.onStart();
}
return service;
}
进入DisplayManagerService的构造方法中,可以看出只是构造一个包含handler的环境。
public DisplayManagerService(Context context) {
super(context);
mContext = context;
mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
mUiHandler = UiThread.getHandler();
mDisplayAdapterListener = new DisplayAdapterListener();
mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
}
将该服务添加到SystemServiceManager的内部列表中后,就会服务的onStart方法:
public void onStart() {
mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
true /*allowIsolated*/);//将BinderService服务添加到servicemanager中
publishLocalService(DisplayManagerInternal.class, new LocalService());//将LocalService服务添加到LocalServices中
}
可以深入两个方法看看,其实现都在SystemService中,这个类是常见系统服务的父类如PowerManagerService等。
protected final void publishBinderService(String name, IBinder service,
boolean allowIsolated) {
ServiceManager.addService(name, service, allowIsolated);
}
/**
* Publish the service so it is only accessible to the system process.
*从注释可以看出,只让系统进程能获取到,说明这些服务不是binder服务,
*如何让系统服务获取呢,就是添加到LocalServices中,这是个静态类,系统进程通过静态类来添加和获取
*/
protected final void publishLocalService(Class type, T service) {
LocalServices.addService(type, service);
}
这个LocalServices其实就是一个静态类,负责提供内部服务:
public final class LocalServices {
private static final ArrayMap, Object> sLocalServiceObjects =
new ArrayMap, Object>();
public static void addService(Class type, T service) {
synchronized (sLocalServiceObjects) {
sLocalServiceObjects.put(type, service);
}
}
}
其内部也有个Map,负责保存存入LocalServices的类,这些类一般是服务。现在可以知道,在DisplayManagerService的onStart方法中,创建了一个LocalService,并将其加入到LocalServices的列表中,来看看LocalService是什么。
private final class LocalService extends DisplayManagerInternal {
@Override
public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager) {
synchronized (mSyncRoot) {
DisplayBlanker blanker = new DisplayBlanker() {
@Override
public void requestDisplayState(int state) {
// The order of operations is important for legacy reasons.
if (state == Display.STATE_OFF) {
requestGlobalDisplayStateInternal(state);
}
callbacks.onDisplayStateChange(state);
if (state != Display.STATE_OFF) {
requestGlobalDisplayStateInternal(state);
}
}
};
mDisplayPowerController = new DisplayPowerController(
mContext, callbacks, handler, sensorManager, blanker);
}
}
.....
}
LocalService是DisplayManagerInternal的子类,这个DisplayManagerInternal其实是个接口类,LocalService负责实现这几个接口。
至此初始化的第一部分结束,主要是构造服务和环境。
系统服务起来后会调用其systemReady方法:
public void systemReady(IAppOpsService appOps) {
synchronized (mLock) {
mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
mSettingsObserver = new SettingsObserver(mHandler);
mLightsManager = getLocalService(LightsManager.class);
// Initialize display power management.
mDisplayManagerInternal.initPowerManagement(mDisplayPowerCallbacks, mHandler, sensorManager);
// Register for settings changes.
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS_MODE),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ),
false, mSettingsObserver, UserHandle.USER_ALL);
mSystemReadyDone.set(true);
......
updatePowerStateLocked}
}
可以看出在systemready方法中会获取sensormanager,和lightservice等,最重要的是调用initPowerManagement,从上面的分析可以知道mDisplayManagerInternal其实就是DisplayManagerService.LocalService,其initPowerManagerment方法中创建了DisplayPowerController。
public DisplayPowerController(Context context,
DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager, DisplayBlanker blanker) {
mHandler = new DisplayControllerHandler(handler.getLooper());
mCallbacks = callbacks;
mBatteryStats = BatteryStatsService.getService();
mLights = LocalServices.getService(LightsManager.class);
mSensorManager = sensorManager;
mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class);
mBlanker = blanker;
mContext = context;
//获取系统关于背光的一些基础参数
final Resources resources = context.getResources();
final int screenBrightnessSettingMinimum = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMinimum));
mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessDoze));
mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessDim));
mScreenBrightnessDarkConfig = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessDark));
int screenBrightnessRangeMinimum = Math.min(Math.min(
screenBrightnessSettingMinimum, mScreenBrightnessDimConfig),
mScreenBrightnessDarkConfig);
mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
//此处很重要,系统如有背光传感器,则要配置其为true,表明可以使用背光
mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);
mAllowAutoBrightnessWhileDozingConfig = resources.getBoolean(
com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing);
if (mUseSoftwareAutoBrightnessConfig) {
int[] lux = resources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLevels);
int[] screenBrightness = resources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
int lightSensorWarmUpTimeConfig = resources.getInteger(
com.android.internal.R.integer.config_lightSensorWarmupTime);
final float dozeScaleFactor = resources.getFraction(
com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor,
1, 1);
//此处也很重要,如果有背光需要实现两个数组,来确定光感值和系统亮度的关系
Spline screenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
if (screenAutoBrightnessSpline == null) {
mUseSoftwareAutoBrightnessConfig = false;
} else {
int bottom = clampAbsoluteBrightness(screenBrightness[0]);
if (bottom < screenBrightnessRangeMinimum) {
screenBrightnessRangeMinimum = bottom;
}
mAutomaticBrightnessController = new AutomaticBrightnessController(this,
handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
mScreenBrightnessRangeMaximum, dozeScaleFactor);
}
}
mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
mColorFadeFadesConfig = resources.getBoolean(
com.android.internal.R.bool.config_animateScreenLights);
if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
if (mProximitySensor != null) {
mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
TYPICAL_PROXIMITY_THRESHOLD);
}
}
}
上面一大串,最重要的是创建一个AutomaticBrightnessController,这个类主要功能是计算自动背光的值,计算好以后配合一个动画类用来实现背光的平稳过度和一个DisplayPowerState类用来控制显示开关和背光和一个light服务用来直接调用底层native方法控制背光。关于计算方法和参数的设置等,在此不讨论,主要讨论流程,进入AutoBrightnessController构造函数。
public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
int brightnessMin, int brightnessMax, float dozeScaleFactor) {
mCallbacks = callbacks;
mTwilight = LocalServices.getService(TwilightManager.class);
mSensorManager = sensorManager;
mScreenAutoBrightnessSpline = autoBrightnessSpline;
mScreenBrightnessRangeMinimum = brightnessMin;
mScreenBrightnessRangeMaximum = brightnessMax;
mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
mDozeScaleFactor = dozeScaleFactor;
mHandler = new AutomaticBrightnessHandler(looper);
mAmbientLightRingBuffer = new AmbientLightRingBuffer();
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
}
主要是初始化环境,包括获取背光控制传感器。
private void updatePowerStateLocked() {
try {
// Phase 0: Basic state updates.
updateIsPoweredLocked(mDirty);
updateStayOnLocked(mDirty);
updateScreenBrightnessBoostLocked(mDirty);
// Phase 1: Update wakefulness.
// Loop because the wake lock and user activity computations are influenced
// by changes in wakefulness.
final long now = SystemClock.uptimeMillis();
int dirtyPhase2 = 0;
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
updateWakeLockSummaryLocked(dirtyPhase1);
updateUserActivitySummaryLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
// Phase 2: Update display power state.
boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
// Phase 3: Update dream state (depends on display ready signal).
updateDreamLocked(dirtyPhase2, displayBecameReady);
}
private boolean updateDisplayPowerStateLocked(int dirty) {
//根据设置和默认值确定亮度值.
int screenBrightness = mScreenBrightnessSettingDefault;
float screenAutoBrightnessAdjustment = 0.0f;
boolean autoBrightness = (mScreenBrightnessModeSetting ==
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
if (autoBrightness) {
screenBrightness = mScreenBrightnessSettingDefault;
if (isValidAutoBrightnessAdjustment(
mTemporaryScreenAutoBrightnessAdjustmentSettingOverride)) {
screenAutoBrightnessAdjustment =
mTemporaryScreenAutoBrightnessAdjustmentSettingOverride;
} else if (isValidAutoBrightnessAdjustment(
mScreenAutoBrightnessAdjustmentSetting)) {
screenAutoBrightnessAdjustment = mScreenAutoBrightnessAdjustmentSetting;
}
}
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;
mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
mRequestWaitForNegativeProximity = false;
}
return mDisplayReady && !oldDisplayReady;
}
调用DisplayManagerService.LocalService的requestPowerState的方法:
@Override
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
return mDisplayPowerController.requestPowerState(request,
waitForNegativeProximity);
}
public boolean requestPowerState(DisplayPowerRequest request,boolean waitForNegativeProximity) {
synchronized (mLock) {
boolean changed = false;
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;
}
}
private void sendUpdatePowerStateLocked() {
if (!mPendingUpdatePowerStateLocked) {
mPendingUpdatePowerStateLocked = true;
Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_POWER_STATE:
updatePowerState();
break;
updatePowerState方法很重要,后面我们还会碰到它:
private void updatePowerState() {
synchronized (mLock) {
mPendingUpdatePowerStateLocked = false;
if (mPowerRequest == null) {
mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
mPendingWaitForNegativeProximityLocked = false;
mPendingRequestChangedLocked = false;
mustInitialize = true;
} else if (mPendingRequestChangedLocked) {
autoBrightnessAdjustmentChanged = (mPowerRequest.screenAutoBrightnessAdjustment
!= mPendingRequestLocked.screenAutoBrightnessAdjustment);
mPowerRequest.copyFrom(mPendingRequestLocked);
mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
mPendingWaitForNegativeProximityLocked = false;
mPendingRequestChangedLocked = false;
mDisplayReadyLocked = false;
}
mustNotify = !mDisplayReadyLocked;
}
// Initialize things the first time the power state is changed.
if (mustInitialize) {
initialize();
}
// Compute the basic display state using the policy.
// We might override this below based on other factors.
int state;
int brightness = PowerManager.BRIGHTNESS_DEFAULT;
boolean performScreenOffTransition = false;
switch (mPowerRequest.policy) {
case DisplayPowerRequest.POLICY_OFF:
state = Display.STATE_OFF;
performScreenOffTransition = true;
break;
case DisplayPowerRequest.POLICY_DOZE:
if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) {
state = mPowerRequest.dozeScreenState;
} else {
state = Display.STATE_DOZE;
}
if (!mAllowAutoBrightnessWhileDozingConfig) {
brightness = mPowerRequest.dozeScreenBrightness;
}
break;
case DisplayPowerRequest.POLICY_DIM:
case DisplayPowerRequest.POLICY_BRIGHT:
default:
state = Display.STATE_ON;
break;
}
// Animate the screen state change unless already animating.
// The transition may be deferred, so after this point we will use the
// actual state instead of the desired one.
animateScreenStateChange(state, performScreenOffTransition);
state = mPowerState.getScreenState();
// 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);
}
// Apply auto-brightness.
boolean slowChange = false;
if (brightness < 0) {
if (autoBrightnessEnabled) {
brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
}
if (brightness >= 0) {
// Use current auto-brightness value and slowly adjust to changes.
brightness = clampScreenBrightness(brightness);
if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
slowChange = true; // slowly adapt to auto-brightness
}
mAppliedAutoBrightness = true;
} else {
mAppliedAutoBrightness = false;
}
} else {
mAppliedAutoBrightness = false;
}
// Apply manual brightness.
// Use the current brightness setting from the request, which is expected
// provide a nominal default value for the case where auto-brightness
// is not ready yet.
if (brightness < 0) {
if(mPowerRequest.screenBrightness != 0 || ActionsConfig.ACTIONS_FEATURE_HDMI_ONOFF_DEFAULT_ON == 0){
// ActionsCode(authro:songzhining, comment: fix brighten bug from dim to off state)
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_OFF) {
brightness = clampScreenBrightness(mPowerState.getScreenBrightness());
} else {
brightness = clampScreenBrightness(mPowerRequest.screenBrightness);
}
}else{
brightness = 0;
}
}
// Animate the screen brightness when the screen is on or dozing.
// Skip the animation when the screen is off or suspended.
if (!mPendingScreenOff) {
if (state == Display.STATE_ON || state == Display.STATE_DOZE) {
animateScreenBrightness(brightness,
slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
} else {
animateScreenBrightness(brightness, 0);
}
}
// Determine whether the display is ready for use in the newly requested state.
// Note that we do not wait for the brightness ramp animation to complete before
// reporting the display is ready because we only need to ensure the screen is in the
// right power state even as it continues to converge on the desired brightness.
final boolean ready = mPendingScreenOnUnblocker == null
&& !mColorFadeOnAnimator.isStarted()
&& !mColorFadeOffAnimator.isStarted()
&& mPowerState.waitUntilClean(mCleanListener);
final boolean finished = ready
&& !mScreenBrightnessRampAnimator.isAnimating();
// Grab a wake lock if we have unfinished business.
if (!finished && !mUnfinishedBusiness) {
if (DEBUG) {
Slog.d(TAG, "Unfinished business...");
}
mCallbacks.acquireSuspendBlocker();
mUnfinishedBusiness = true;
}
// Notify the power manager when ready.
if (ready && mustNotify) {
// Send state change.
synchronized (mLock) {
if (!mPendingRequestChangedLocked) {
mDisplayReadyLocked = true;
if (DEBUG) {
Slog.d(TAG, "Display ready!");
}
}
}
sendOnStateChangedWithWakelock();
}
// Release the wake lock when we have no unfinished business.
if (finished && mUnfinishedBusiness) {
if (DEBUG) {
Slog.d(TAG, "Finished business...");
}
mUnfinishedBusiness = false;
mCallbacks.releaseSuspendBlocker();
}
}
在updatepowerstate中首先通过initialize方法初始化控制背光的环境,即创建相应的类包括动画控制类等;然后通过configure方法配置是否打开关闭自动背光,也就是要不要打开光感;最后通过animateScreenBrightness来将得到的brightness值配置到底层。
private void initialize() {
// Initialize the power state object for the default display.
// In the future, we might manage multiple displays independently.
mPowerState = new DisplayPowerState(mBlanker,
mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
new ColorFade(Display.DEFAULT_DISPLAY));
mScreenBrightnessRampAnimator = new RampAnimator(
mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
}
创建一个DisplayPowerState,作为控制屏幕的类,这个类是控制屏幕亮灭和亮度的接口。RampAnimator这个类是泛型
public DisplayPowerState(DisplayBlanker blanker, Light backlight, ColorFade electronBeam) {
mHandler = new Handler(true /*async*/);
mChoreographer = Choreographer.getInstance();
mBlanker = blanker;
mBacklight = backlight;
mColorFade = electronBeam;
mPhotonicModulator = new PhotonicModulator();
mPhotonicModulator.start();
// At boot time, we know that the screen is on and the electron beam
// animation is not playing. We don't know the screen's brightness though,
// so prepare to set it to a known state when the state is next applied.
// Although we set the brightness to full on here, the display power controller
// will reset the brightness to a new level immediately before the changes
// actually have a chance to be applied.
mScreenState = Display.STATE_ON;
mScreenBrightness = PowerManager.BRIGHTNESS_ON;
scheduleScreenUpdate();
mColorFadePrepared = false;
mColorFadeLevel = 1.0f;
mColorFadeReady = true;
}
public static final IntProperty SCREEN_BRIGHTNESS =
new IntProperty("screenBrightness") {
@Override
public void setValue(DisplayPowerState object, int value) {
object.setScreenBrightness(value);
}
@Override
public Integer get(DisplayPowerState object) {
return object.getScreenBrightness();
}
};
final class RampAnimator {
private final T mObject;//泛型
private final IntProperty mProperty;
private final Choreographer mChoreographer;
private int mCurrentValue;
private int mTargetValue;
private int mRate;
private boolean mAnimating;
private float mAnimatedValue; // higher precision copy of mCurrentValue
private long mLastFrameTimeNanos;
private boolean mFirstTime = true;
private Listener mListener;
public RampAnimator(T object, IntProperty property) {
mObject = object;
mProperty = property;
mChoreographer = Choreographer.getInstance();
}
}
2.1.2 configure方法
public 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 setLightSensorEnabled(boolean enable) {
if (enable) {
if (!mLightSensorEnabled) {
mLightSensorEnabled = true;
mLightSensorEnableTime = SystemClock.uptimeMillis();
mSensorManager.registerListener(mLightSensorListener, mLightSensor,
LIGHT_SENSOR_RATE_MILLIS * 1000, mHandler);//申请光感
return true;
}
} else {
if (mLightSensorEnabled) {
mLightSensorEnabled = false;
mAmbientLuxValid = false;
mRecentLightSamples = 0;
mAmbientLightRingBuffer.clear();
mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
mSensorManager.unregisterListener(mLightSensorListener);
}
}
return false;
}
private void animateScreenBrightness(int target, int rate) {
if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
try {
mBatteryStats.noteScreenBrightness(target);
} catch (RemoteException ex) {
// same process
}
}
}
调用animateTo方法,从上面的分析可知mScreenBrightRampAnimator是一个泛型,看起animateTo方法:
public boolean animateTo(int target, int rate) {
// Immediately jump to the target the first time.此时应该是第一次调用,会走这个分支
if (mFirstTime || rate <= 0) {
if (mFirstTime || target != mCurrentValue) {
mFirstTime = false;
mRate = 0;
mTargetValue = target;
mCurrentValue = target;
mProperty.setValue(mObject, target);
if (mAnimating) {
mAnimating = false;
cancelAnimationCallback();
}
if (mListener != null) {
mListener.onAnimationEnd();
}
return true;
}
return false;
}
// Adjust the rate based on the closest target.
// If a faster rate is specified, then use the new rate so that we converge
// more rapidly based on the new request.
// If a slower rate is specified, then use the new rate only if the current
// value is somewhere in between the new and the old target meaning that
// we will be ramping in a different direction to get there.
// Otherwise, continue at the previous rate.
if (!mAnimating
|| rate > mRate
|| (target <= mCurrentValue && mCurrentValue <= mTargetValue)
|| (mTargetValue <= mCurrentValue && mCurrentValue <= target)) {
mRate = rate;
}
final boolean changed = (mTargetValue != target);
mTargetValue = target;
// Start animating.
if (!mAnimating && target != mCurrentValue) {
mAnimating = true;
mAnimatedValue = mCurrentValue;
mLastFrameTimeNanos = System.nanoTime();
postAnimationCallback();
}
return changed;
}
从注释可以,第一次会直接设置值,并不会有一个亮度渐变的动画过程。从mScreenBrightRampAnimator的构造方法可知,这个mProperty就是DisplayPowerState.SCREEN_BRIGHTNESS,所以mProperty.setValue(mObject, target);其实就是调用
object.setScreenBrightness(value);即DisplayPowerState的setScreenBrightness(value);方法。
/**
* Sets the display brightness.
*
* @param brightness The brightness, ranges from 0 (minimum / off) to 255 (brightest).
*/
public void setScreenBrightness(int brightness) {
if (mScreenBrightness != brightness) {
mScreenBrightness = brightness;
if (mScreenState != Display.STATE_OFF) {
mScreenReady = false;
scheduleScreenUpdate();
}
}
}
private void scheduleScreenUpdate() {
if (!mScreenUpdatePending) {
mScreenUpdatePending = true;
postScreenUpdateThreadSafe();
}
}
private void postScreenUpdateThreadSafe() {
mHandler.removeCallbacks(mScreenUpdateRunnable);
mHandler.post(mScreenUpdateRunnable);
}
private final Runnable mScreenUpdateRunnable = new Runnable() {
@Override
public void run() {
mScreenUpdatePending = false;
int brightness = mScreenState != Display.STATE_OFF
&& mColorFadeLevel > 0f ? mScreenBrightness : 0;
if (mPhotonicModulator.setState(mScreenState, brightness)) {
mScreenReady = true;
invokeCleanListenerIfNeeded();
}
};
public boolean setState(int state, int backlight) {
synchronized (mLock) {
if (state != mPendingState || backlight != mPendingBacklight) {
mPendingState = state;//屏的状态并未改变
mPendingBacklight = backlight;//本次设置是改变背光值
if (!mChangeInProgress) {
mChangeInProgress = true;
mLock.notifyAll();
}
}
return !mChangeInProgress;
}
}
从DisplayPowerState的构造方法可知会创建一个PhotonicModulator,并调用其start方法,可知其继承了Thread类。
public void run() {
for (;;) {
// Get pending change.
final int state;
final boolean stateChanged;
final int backlight;
final boolean backlightChanged;
synchronized (mLock) {
state = mPendingState;
stateChanged = (state != mActualState);//未变
backlight = mPendingBacklight;
backlightChanged = (backlight != mActualBacklight);//改变
mActualState = state;
mActualBacklight = backlight;
}
// Apply pending change.
boolean suspending = Display.isSuspendedState(state);
if (stateChanged && !suspending) {
requestDisplayState(state);
}
if (backlightChanged) {
setBrightness(backlight);
}
if (stateChanged && suspending) {
requestDisplayState(state);
}
}
}
调用setBrightness方法:
private void setBrightness(int backlight) {
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setBrightness(" + backlight + ")");
try {
mBacklight.setBrightness(backlight);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
使用Light类的setBrightness方法来控制背光的大小。到此实现了背光的控制。
总结下DisplayPowerState是一个控制背光和亮灭屏的类,通过PhotonicModulator类在另一个线程中实现功能。PhotonicModulator的run方法一直在检查背光和屏状态有没有改变,如果有改变则调用相关方法来实现,实现方式为获取Light来控制亮度;而DisplayPowerState向外界提供setValue方法来设置背光值,让其改变,这个外界其实就是RampAnimator泛型。
至此,背光的开机控制已经实现,下面来分析背光如何根据光感的值来自动调节。
在使能光感的方法中注册了一个回调方法
private final SensorEventListener mLightSensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
if (mLightSensorEnabled) {
final long time = SystemClock.uptimeMillis();
final float lux = event.values[0];
handleLightSensorEvent(time, lux);
}
}
};
private void handleLightSensorEvent(long time, float lux) {
mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
applyLightSensorMeasurement(time, lux);
updateAmbientLux(time);
}
private void updateAmbientLux(long time) {
// If the light sensor was just turned on then immediately update our initial
// estimate of the current ambient light level.光感刚刚被初始化的时候走下面分支
if (!mAmbientLuxValid) {
.....
}
long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
float ambientLux = calculateAmbientLux(time);
if (ambientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
|| ambientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
setAmbientLux(ambientLux);
updateAutoBrightness(true);
nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
}
long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);
nextTransitionTime =
nextTransitionTime > time ? nextTransitionTime : time + LIGHT_SENSOR_RATE_MILLIS;
mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
}
private void updateAutoBrightness(boolean sendUpdate) {
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 (gamma != 1.0f) {
final float in = value;
value = MathUtils.pow(value, gamma);
}
int newScreenAutoBrightness =
clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
if (mScreenAutoBrightness != newScreenAutoBrightness) {
mScreenAutoBrightness = newScreenAutoBrightness;
mLastScreenAutoBrightnessGamma = gamma;
if (sendUpdate) {
mCallbacks.updateBrightness();
}
}
}
调用了DisplayPowerController的updateBrightness方法:
@Override
public void updateBrightness() {
sendUpdatePowerState();
}
最后调用了updatePowerState方法,这个方法在第一次开机设置背光亮度的时候分析过,不同的地方在于animateTo方法中,不是第一次调用了:
public boolean animateTo(int target, int rate) {
// Immediately jump to the target the first time.
if (mFirstTime || rate <= 0) {
....
}
// Start animating.开始进入动画的过程
if (!mAnimating && target != mCurrentValue) {
mAnimating = true;
mAnimatedValue = mCurrentValue;
mLastFrameTimeNanos = System.nanoTime();
postAnimationCallback();
}
return changed;
}
private void postAnimationCallback() {
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null);
}
private final Runnable mAnimationCallback = new Runnable() {
@Override // Choreographer callback
public void run() {
final long frameTimeNanos = mChoreographer.getFrameTimeNanos();
final float timeDelta = (frameTimeNanos - mLastFrameTimeNanos)
* 0.000000001f;
mLastFrameTimeNanos = frameTimeNanos;
// Advance the animated value towards the target at the specified rate
// and clamp to the target. This gives us the new current value but
// we keep the animated value around to allow for fractional increments
// towards the target.
final float scale = ValueAnimator.getDurationScale();
if (scale == 0) {
// Animation off.
mAnimatedValue = mTargetValue;
} else {
final float amount = timeDelta * mRate / scale;
if (mTargetValue > mCurrentValue) {
mAnimatedValue = Math.min(mAnimatedValue + amount, mTargetValue);
} else {
mAnimatedValue = Math.max(mAnimatedValue - amount, mTargetValue);
}
}
final int oldCurrentValue = mCurrentValue;
mCurrentValue = Math.round(mAnimatedValue);
//如果以前的值和当前值不同时,设置值
if (oldCurrentValue != mCurrentValue) {
mProperty.setValue(mObject, mCurrentValue);
}
//如果第一次模拟后还是不能达到目标时,在来一次
if (mTargetValue != mCurrentValue) {
postAnimationCallback();
} else {//如果目标值和当前值相同,证明不需要动画了,调用动画结束的回调
mAnimating = false;
if (mListener != null) {
mListener.onAnimationEnd();
}
}
}
};
所以这个类的名字叫RampAnimator,其实这个类是个工具,任何需要动画设置的硬件都可以使用它。所以它设计为了一个泛型,就是为了可以传入其他的类,让其实现完了计算后要调用传入的泛型的方法如setvale等,注意这个泛型要实现这个setvale方法。这个泛型可以是控制背光的。
总结:
DisplayPowerConntroller:是一个控制类,是自动背光调节的枢纽,联系其他的类。
AutobrightnessConntroller:通过注册光感的回调来获取光感的值,若有改变则,updateAutoBrightness即更新brightness值,然后通过回调来通知到DisplayPowerConntroller,最后调用DisplayPowerConntroller的updatePowerState方法。
RampAnimator:在updatePowerState方法中会调用mScreenBrightRampAnimator的animateTo方法,这里会传入一个brightness目标值,而在animateTo中则会通过一个循环一点点逼近这个目标值,从而实现动画的效果。
DisplayPowerState:在循环过程中会调用DisplayPowerState.SCREEN_BRIGHTNESS方法来设置亮度值,即调用到DisplayPowerState.setScreenBrightness。setScreenBrightness最后会执行一个runnable,在该runnable中调用mPhotonicModulator.setState来设置State和brightness。
PhotonicModulator:在构造DisplayPowerState时就会创建PhotonicModulator,它继承Thread,会一直跑一个线程,在该线程中一直会检测State和brightness有没有改变,如果改变就会调用mBacklight.setBrightness(backlight);来设置背光值。
关于systemui和setting中亮度设置的不同步