Android5.1 背光控制分析

本文主要讲述android5.1系统对背光的处理,从初始化到点击自动背光模式再到UI的同步处理,文章分为三点讲述:

1.背光的初始化

2.自动背光的调用过程:从点击setting中自动调节亮度开始

3.systemUI和setting对背光模式的同步

一:初始化

1.1控制背光服务的启动

大部分的服务的起点都在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 extends SystemService> T startService(Class<T> serviceClass) {
        final String name = serviceClass.getName();
        // 创建该服务,创建的服务都是SystemService的子类,需要实现onStart方法。
        final T service;
        try {
            Constructor<T> 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 <T> void publishLocalService(Class<T> type, T service) {
        LocalServices.addService(type, service);
    }

这个LocalServices其实就是一个静态类,负责提供内部服务:

public final class LocalServices {
    private static final ArrayMap<Class<?>, Object> sLocalServiceObjects =
            new ArrayMap<Class<?>, Object>();
    public static <T> void addService(Class<T> 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负责实现这几个接口。

至此初始化的第一部分结束,主要是构造服务和环境。

1.2PowerManagerService.SystemReady方法

系统服务起来后会调用其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}
}

1.2.1 initPowerManagement

可以看出在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);
    }
主要是初始化环境,包括获取背光控制传感器。

二:开机背光控制和自动调节过程

2.1 开机背光控制

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值配置到底层。

2.1.1 首先看看initialize方法:

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<DisplayPowerState>(
                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<DisplayPowerState> SCREEN_BRIGHTNESS =
            new IntProperty<DisplayPowerState>("screenBrightness") {
        @Override
        public void setValue(DisplayPowerState object, int value) {
            object.setScreenBrightness(value);
        }

        @Override
        public Integer get(DisplayPowerState object) {
            return object.getScreenBrightness();
        }
    };



final class RampAnimator<T> {
    private final T mObject;//泛型
    private final IntProperty<T> 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<T> 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;
    }

2.1.3 animateScreenBrightness


    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泛型。

至此,背光的开机控制已经实现,下面来分析背光如何根据光感的值来自动调节。

2.2背光自动调节过程


在使能光感的方法中注册了一个回调方法

    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();
                }
            }
        }
    };

从上述代码可知,这是个循环,postAnimationCallback会一直调用,直到调节到需要的值才会停止,所以就会有动画的效果。

    所以这个类的名字叫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中亮度设置的不同步


       

猜你喜欢

转载自blog.csdn.net/ywlyg/article/details/79584916