Android 系统背光设置

一、一般设置

1、手动设置背光API

// 修改当前Activity界面的窗口亮度
private void setScreenLight(int brightness) {
    WindowManager.LayoutParams lp = getWindow().getAttributes();
    lp.screenBrightness = Float.valueOf(brightness) * (1f / 255f);
    getWindow().setAttributes(lp);
}

// 修改系统的亮度值
public void setScreenLight(int brightness) {
    Uri uri = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
    ContentResolver contentResolver = getContentResolver();
    Settings.System.putInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS, brightness);
    contentResolver.notifyChange(uri, null);
}

 

2、设置系统背光默认亮度值

#frameworks/base/core/res/res/values/config.xml

<integer name="config_screenBrightnessSettingMinimum">2</integer>
<integer name="config_screenBrightnessDim">2</integer>

系统背光节点路径:/sys/class/leds/lcd-backlight/brightness

 

3、自动背光配置设置

自动背光涉及光感值与亮度值对应,需要根据项目进行设置光感和背光值数组,一一对应

# frameworks/base/core/res/res/values/config.xml

<integer-array name="config_autoBrightnessLevels">
... 填写亮度值数组 ...
</integer-array>

<integer-array name="config_autoBrightnessLcdBacklightValues">
... 填写光感值数组 ...
</integer-array>

 

二、流程分析

系统手动设置,待机休眠等都是通过 PowerManagerService.java 统一管理,自动背光则是由 AutomaticBrightnessController.java 管理。最后统一调用 DisplayPowerController.java 进行处理。

 1、frameworks/base/services/core/java/com/android/server/display/AutomaticBrightnessController.java  主要相关操作:

通过监听L-sersor 值变化发送 handleLightSensorEvent  走到  updateAutoBrightness 函数,最终调用到 DisplayPowerController.java updateBrightness函数。

// 内部创建一个光感监听
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);
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Not used.
    }
};

// 通知update背光
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(mScreenAutoBrightnessAdjustmentMaxGamma,
                Math.min(1.0f, Math.max(-1.0f, -mScreenAutoBrightnessAdjustment)));
        gamma *= adjGamma;
        if (DEBUG) {
            Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
        }
    }

    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背光改变,mCallbacks 即是 DisplayPowerController 类对象
            mCallbacks.updateBrightness();
        }
    }
}

// mCallbacks中调用获取当前的自动背光值,后续进行设置
public int getAutomaticScreenBrightness() {
    if (!mAmbientLuxValid) {
        return -1;
    }
    if (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE) {
        return (int) (mScreenAutoBrightness * mDozeScaleFactor);
    }
    return mScreenAutoBrightness;
}



 

2、frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java 主要操作:

上层背光相关操作最终都是走到 PowerManagerService ,统一处理,这里只看设置 SCREEN_BRIGHTNESS 值的流程。通过 SettingsObserver 监听值变化,最终调用到 DisplayPowerController.java requestPowerState 函数。

// 系统启动时进行初始化操作
public void systemReady(IAppOpsService appOps) {
    ... ...

    // 绑定监听
    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);
    ... ...
}

// 监听变化发送 handleSettingsChangedLocked
private final class SettingsObserver extends ContentObserver {
    public SettingsObserver(Handler handler) {
        super(handler);
    }

    @Override
    public void onChange(boolean selfChange, Uri uri) {
        synchronized (mLock) {
            handleSettingsChangedLocked();
        }
    }
}

//handleSettingsChangedLocked -> updatePowerStateLocked -> updateDisplayPowerStateLocked 
/**
 *异步更新显示电源状态。 更新完成后,mDisplayReady将设置为true。 显示控制器会发布一条消息,告诉 
 *我们实际的显示电源状态何时已更新,因此我们回到这里进行仔细检查并完成。
 *每次该功能都会重新计算显示功率状态。
 *@return如果显示准备就绪,则为True。
*/
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 | DIRTY_VR_MODE_CHANGED |
            DIRTY_QUIESCENT)) != 0) {
        mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();
        ... ...

        // 修改更新 mDisplayPowerRequest 亮度值等属性
        mDisplayPowerRequest.screenBrightnessOverride = screenBrightnessOverride;
        mDisplayPowerRequest.useAutoBrightness = autoBrightness;
        mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
        mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();

        updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest);
        ... ...        
        // 最终调用 DisplayPowerController 处理
        mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,mRequestWaitForNegativeProximity);
        ... ...
    }
    return mDisplayReady && !oldDisplayReady;
}

 

3、frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java 主要相关方法分析

通过  Settings.System.SCREEN_BRIGHTNESS 手动设置值,是从调用 requestPowerState 开始,最终调用 sendUpdatePowerStateLocked,如下

// 通过设置settings值手动更新亮度调用
public boolean requestPowerState(DisplayPowerRequest request,
        boolean waitForNegativeProximity) {
    if (DEBUG) {
        Slog.d(TAG, "requestPowerState: "
                + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
    }

    synchronized (mLock) {
        boolean changed = false;

        mRequestPowerStateChangedByUser = 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;
            mRequestPowerStateChangedByUser = true;
        }

        if (changed) {
            mDisplayReadyLocked = false;
        }

        if (changed && !mPendingRequestChangedLocked) {
            mPendingRequestChangedLocked = true;
            // 通知更新亮度
            sendUpdatePowerStateLocked();
        }

        return mDisplayReadyLocked;
    }
}

自动背光调节的流程调用是从 updateBrightness() 开始,最终也是调用 sendUpdatePowerStateLocked,如下

@Override
public void updateBrightness() {
    sendUpdatePowerState();
}

private void sendUpdatePowerState() {
    synchronized (mLock) {
        sendUpdatePowerStateLocked();
    }
}

sendUpdatePowerStateLocked  这个函数就是手动、自动亮度调节最终统一的地方。它里面只是简单的通过handler 发送调用 updatePowerState();updatePowerState() 里面才是真正进行操作的地方。

private void updatePowerState() {
    // Update the power state request.
    ... ...

    // P-Sensor的靠近操作
    if (mProximitySensor != null) {
        ... ...
    } else {
        mWaitingForNegativeProximity = false;
    }
    if (mScreenOffBecauseOfProximity) {
        state = Display.STATE_OFF;
    }

    // 配置自动亮度值
    boolean slowChange = false;
    if (brightness < 0) {
        if (autoBrightnessEnabled) {
            // 这里就是获取 AutomaticBrightnessController 保存的自动亮度值
            brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
        }
        if (brightness >= 0) {
            // 这里就是保证 brightness 在系统最小最大设置值 10 ~ 255 之间
            // 具体看 frameworks/base/core/res/res/values/config.xml 中 config_screenBrightnessSettingMinimum config_screenBrightnessSettingMaximum 值
            brightness = clampScreenBrightness(brightness);
            if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
                slowChange = true; // slowly adapt to auto-brightness
            }
            mAppliedAutoBrightness = true;
        } else {
            mAppliedAutoBrightness = false;
        }
    } else {
        mAppliedAutoBrightness = false;
    }

    // Use default brightness when dozing unless overridden.
    if (brightness < 0 && (state == Display.STATE_DOZE
            || state == Display.STATE_DOZE_SUSPEND)) {
        brightness = mScreenBrightnessDozeConfig;
    }

    // 这里是我自己添加判断,过滤重复设置亮度
    // 保存自动亮度值 mRequestPowerStateAutoBrightness。
    // 如果 mRequestPowerStateChangedByUser 手动操作为false,且mRequestPowerStateAutoBrightness也没有变化,就直接return
    if (mRequestPowerStateAutoBrightness != brightness) {
        mRequestPowerStateAutoBrightness = brightness;
    } else if (!mRequestPowerStateChangedByUser) {
        Slog.d(TAG, "Brightness no changed");
        return;
    }

    // 这里使用手动亮度值
    Slog.d(TAG, "Apply manual brightness " + brightness + " " + mRequestPowerStateAutoBrightness);
    if (brightness < 0 || mRequestPowerStateChangedByUser) {
        int clampBrightness = clampScreenBrightness(mPowerRequest.screenBrightness);
        if (brightness == clampBrightness) {
            Slog.d(TAG, "RequestPowerStateChangedByUser Brightness no changed");
            return;
        }
        brightness = clampBrightness;
    }

    // 这里就是系统自动休眠前,先变暗一会
    if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
        if (brightness > mScreenBrightnessRangeMinimum) {
            brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
                    mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
        }
        if (!mAppliedDimming) {
            slowChange = false;
        }
        mAppliedDimming = true;
    } else if (mAppliedDimming) {
        slowChange = false;
        mAppliedDimming = false;
    }
    ... ...

    // 判断屏幕是否是off
    if (!mPendingScreenOff) {
        ... ...

        // 通过判断确定背光响应变化速度
        // mBrightnessRampRateSlow 原生是60,是1s调整60亮度
        // mBrightnessRampRateFast 原生是180,是1s调整180亮度
        boolean wasOrWillBeInVr = (state == Display.STATE_VR || oldState == Display.STATE_VR);
        if (!mRequestPowerStateChangedByUser && (state == Display.STATE_ON
                && mSkipRampState == RAMP_STATE_SKIP_NONE
                || state == Display.STATE_DOZE && !mBrightnessBucketsInDozeConfig)
                && !wasOrWillBeInVr) {
            // 一般自动亮度变化是会渐变调整的
            animateScreenBrightness(brightness,
                    slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
        } else {
            // 手动一般是立即变化的,无需动画渐变调整的
            animateScreenBrightness(brightness, 0);
        }
        Slog.d(TAG, "putInt brightness " + brightness);
    }
    ... ...

}

animateScreenBrightness 内部逻辑是在 frameworks/base/services/core/java/com/android/server/display/RampAnimator.java 中 animateTo 处理。

animateTo 中调用 postAnimationCallback ,在 mAnimationCallback 中一直设置值渐变。

private void postAnimationCallback() {
    mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null);
}

private void cancelAnimationCallback() {
    mChoreographer.removeCallbacks(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);
        }

        // mCurrentValue 当前值 
        // mTargetValue 目标值
        if (mTargetValue != mCurrentValue) {
            postAnimationCallback();
        } else {
            mAnimating = false;
            if (mListener != null) {
                // 通知变化完成
                mListener.onAnimationEnd();
            }
        }
    }
};

mProperty.setValue(mObject, mCurrentValue); 

这个方法就是实际操作写入背光值的地方,往下就是通过 native 调用处理。到这里背光设置就完成了。

 

 

 

 

 

 

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值