平台

 RK3399 + Android 9.0

概述

 众所周知, Android 平台的上层亮度值的设置值范围为[0, 255], 在9.0之前, 亮度调节一直是线性变化, 在9.0开始, 它变成了曲线变化, 如下图:
在这里插入图片描述
         图1-实际亮度值: 11
在这里插入图片描述
         图2-实际亮度值: 15
在这里插入图片描述
         图3-实际亮度值: 33
在这里插入图片描述
         图4-实际亮度值: 105
在这里插入图片描述
         图5-实际亮度值: 255

 其中图3最直观体现与线性变化的区别, 进度条在50%以上, 那么实际亮度值应该接近122.

进度条亮度值
13011
24215
54133
843105
1023255

流程

 亮度调节有两个常见的入口: 设置 和 状态栏.

  • 设置

packages/Settings/AndroidManifest.xml

 <activity
            android:name="Settings$DisplaySettingsActivity"
            android:label="@string/display_settings"
            android:icon="@drawable/ic_homepage_display"
            android:taskAffinity="com.android.settings"
            android:parentActivityName="Settings">
            <intent-filter android:priority="1">
                <action android:name="com.android.settings.DISPLAY_SETTINGS" />
                <action android:name="android.settings.DISPLAY_SETTINGS" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.VOICE_LAUNCH" />
                <category android:name="com.android.settings.SHORTCUT" />
            </intent-filter>
            <intent-filter android:priority="7">
                <action android:name="com.android.settings.action.SETTINGS" />
            </intent-filter>
            <meta-data android:name="com.android.settings.category"
                android:value="com.android.settings.category.ia.homepage" />
            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
                android:value="com.android.settings.DisplaySettings" />
            <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
                android:value="true" />
            <meta-data android:name="com.android.settings.summary"
                android:resource="@string/display_dashboard_summary"/>
        </activity>

        <!-- Keep compatibility with old shortcuts. -->
        <activity-alias android:name="DisplaySettings"
                android:label="@string/display_settings"
                android:exported="true"
                android:targetActivity="Settings$DisplaySettingsActivity">
            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
                android:value="com.android.settings.DisplaySettings" />
        </activity-alias>

packages/apps/Settings/src/com/android/settings/DisplaySettings.java

public class DisplaySettings extends DashboardFragment {
    private static final String TAG = "DisplaySettings";

    public static final String KEY_DISPLAY_SIZE = "display_settings_screen_zoom";

    private static final String KEY_SCREEN_TIMEOUT = "screen_timeout";
    private static final String KEY_AMBIENT_DISPLAY = "ambient_display";
    private static final String KEY_AUTO_BRIGHTNESS = "auto_brightness_entry";
    private static final String KEY_NIGHT_DISPLAY = "night_display";
    private static final String KET_HDMI_SETTINGS = "hdmi_settings";

    @Override
    public int getMetricsCategory() {
        return MetricsEvent.DISPLAY;
    }

    @Override
    protected String getLogTag() {
        return TAG;
    }

    @Override
    protected int getPreferenceScreenResId() {
        return R.xml.display_settings;
    }
    //...
}

packages/apps/Settings/res/xml/display_settings.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:settings="http://schemas.android.com/apk/res-auto"
    android:key="display_settings_screen"
    android:title="@string/display_settings"
    settings:keywords="@string/keywords_display"
    settings:initialExpandedChildrenCount="4">

    <com.android.settingslib.RestrictedPreference
        android:key="brightness"
        android:title="@string/brightness"
        settings:keywords="@string/keywords_display_brightness_level"
        settings:useAdminDisabledSummary="true"
        settings:userRestriction="no_config_brightness">
        <intent android:action="com.android.intent.action.SHOW_BRIGHTNESS_DIALOG" />
    </com.android.settingslib.RestrictedPreference>
    ....

 当点击亮度设置后, 会打开亮度调节窗口:
com.android.intent.action.SHOW_BRIGHTNESS_DIALOG
 参照下面状态栏部分

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.QuickSettings.Dialog"
            android:finishOnCloseSystemDialogs="true"
            android:launchMode="singleInstance"
            android:excludeFromRecents="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.android.intent.action.SHOW_BRIGHTNESS_DIALOG" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
  • 状态栏

frameworks/base/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java

/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.settings;

import android.app.Activity;
import android.os.Bundle;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;

/** A dialog that provides controls for adjusting the screen brightness. */
public class BrightnessDialog extends Activity {

    private BrightnessController mBrightnessController;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final Window window = getWindow();

        window.setGravity(Gravity.TOP);
        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        window.requestFeature(Window.FEATURE_NO_TITLE);

        // Use a dialog theme as the activity theme, but inflate the content as
        // the QS content.
        ContextThemeWrapper themedContext = new ContextThemeWrapper(this,
                com.android.internal.R.style.Theme_DeviceDefault_QuickSettings);
        View v = LayoutInflater.from(themedContext).inflate(
                R.layout.quick_settings_brightness_dialog, null);
        setContentView(v);

        final ImageView icon = findViewById(R.id.brightness_icon);
        final ToggleSliderView slider = findViewById(R.id.brightness_slider);
        mBrightnessController = new BrightnessController(this, icon, slider);
    }

    @Override
    protected void onStart() {
        super.onStart();
        mBrightnessController.registerCallbacks();
        MetricsLogger.visible(this, MetricsEvent.BRIGHTNESS_DIALOG);
    }

    @Override
    protected void onStop() {
        super.onStop();
        MetricsLogger.hidden(this, MetricsEvent.BRIGHTNESS_DIALOG);
        mBrightnessController.unregisterCallbacks();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
                || keyCode == KeyEvent.KEYCODE_VOLUME_UP
                || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
            finish();
        }

        return super.onKeyDown(keyCode, event);
    }
}

 UI部分主要就一个ToggleSliderView, 主要的一些逻辑操作都放在BrightnessController中, 进度条变化后的回调函数:

frameworks/base/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java

    @Override
    public void onChanged(ToggleSlider toggleSlider, boolean tracking, boolean automatic,
            int value, boolean stopTracking) {
        updateIcon(mAutomatic);
        if (mExternalChange) return;

        if (mSliderAnimator != null) {
            mSliderAnimator.cancel();
        }

        final int min;
        final int max;
        final int metric;
        final String setting;

        if (mIsVrModeEnabled) {
            metric = MetricsEvent.ACTION_BRIGHTNESS_FOR_VR;
            min = mMinimumBacklightForVr;
            max = mMaximumBacklightForVr;
            setting = Settings.System.SCREEN_BRIGHTNESS_FOR_VR;
        } else {
            metric = mAutomatic
                    ? MetricsEvent.ACTION_BRIGHTNESS_AUTO
                    : MetricsEvent.ACTION_BRIGHTNESS;
            min = mMinimumBacklight;
            max = mMaximumBacklight;
            setting = Settings.System.SCREEN_BRIGHTNESS;
        }

        final int val = convertGammaToLinear(value, min, max);

        if (stopTracking) {
            MetricsLogger.action(mContext, metric, val);
        }

        setBrightness(val);
        if (!tracking) {
            AsyncTask.execute(new Runnable() {
                    public void run() {
                        Settings.System.putIntForUser(mContext.getContentResolver(),
                                setting, val, UserHandle.USER_CURRENT);
                    }
                });
        }

        for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
            cb.onBrightnessLevelChanged();
        }
    }

 转换曲线: convertGammaToLinear(value, min, max); 和 convertLinearToGamma(int val, int min, int max)

frameworks/base/packages/SettingsLib/src/com/android/settingslib/display/BrightnessUtils.java

/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settingslib.display;

import android.util.MathUtils;

public class BrightnessUtils {

    public static final int GAMMA_SPACE_MAX = 1023;
    public static final boolean ENABLE_GAMMA = false;

    // Hybrid Log Gamma constant values
    private static final float R = 0.5f;
    private static final float A = 0.17883277f;
    private static final float B = 0.28466892f;
    private static final float C = 0.55991073f;

    /**
     * A function for converting from the gamma space that the slider works in to the
     * linear space that the setting works in.
     *
     * The gamma space effectively provides us a way to make linear changes to the slider that
     * result in linear changes in perception. If we made changes to the slider in the linear space
     * then we'd see an approximately logarithmic change in perception (c.f. Fechner's Law).
     *
     * Internally, this implements the Hybrid Log Gamma electro-optical transfer function, which is
     * a slight improvement to the typical gamma transfer function for displays whose max
     * brightness exceeds the 120 nit reference point, but doesn't set a specific reference
     * brightness like the PQ function does.
     *
     * Note that this transfer function is only valid if the display's backlight value is a linear
     * control. If it's calibrated to be something non-linear, then a different transfer function
     * should be used.
     *
     * @param val The slider value.
     * @param min The minimum acceptable value for the setting.
     * @param max The maximum acceptable value for the setting.
     * @return The corresponding setting value.
     */
    public static final int convertGammaToLinear(int val, int min, int max) {
        final float normalizedVal = MathUtils.norm(0, GAMMA_SPACE_MAX, val);
        final float ret;
        if (normalizedVal <= R) {
            ret = MathUtils.sq(normalizedVal / R);
        } else {
            ret = MathUtils.exp((normalizedVal - C) / A) + B;
        }

        // HLG is normalized to the range [0, 12], so we need to re-normalize to the range [0, 1]
        // in order to derive the correct setting value.
        return Math.round(MathUtils.lerp(min, max, ret / 12));
    }

    /**
     * A function for converting from the linear space that the setting works in to the
     * gamma space that the slider works in.
     *
     * The gamma space effectively provides us a way to make linear changes to the slider that
     * result in linear changes in perception. If we made changes to the slider in the linear space
     * then we'd see an approximately logarithmic change in perception (c.f. Fechner's Law).
     *
     * Internally, this implements the Hybrid Log Gamma opto-electronic transfer function, which is
     * a slight improvement to the typical gamma transfer function for displays whose max
     * brightness exceeds the 120 nit reference point, but doesn't set a specific reference
     * brightness like the PQ function does.
     *
     * Note that this transfer function is only valid if the display's backlight value is a linear
     * control. If it's calibrated to be something non-linear, then a different transfer function
     * should be used.
     *
     * @param val The brightness setting value.
     * @param min The minimum acceptable value for the setting.
     * @param max The maximum acceptable value for the setting.
     * @return The corresponding slider value
     */
    public static final int convertLinearToGamma(int val, int min, int max) {
        // For some reason, HLG normalizes to the range [0, 12] rather than [0, 1]
        final float normalizedVal = MathUtils.norm(min, max, val) * 12;
        final float ret;
        if (normalizedVal <= 1f) {
            ret = MathUtils.sqrt(normalizedVal) * R;
        } else {
            ret = A * MathUtils.log(normalizedVal - B) + C;
        }

        return Math.round(MathUtils.lerp(0, GAMMA_SPACE_MAX, ret));
    }
}


  • 设置/写入:
    进度条进度 -> convertGammaToLinear -> Settings.System.put

  • 读取
    Settings.System.get -> convertLinearToGamma -> 设置进度条进度

去除曲线功能

 增加ENABLE_GAMMA控制

frameworks/base/packages/SettingsLib/src/com/android/settingslib/display/BrightnessUtils.java

@@ -21,6 +21,7 @@ import android.util.MathUtils;
 public class BrightnessUtils {
 
     public static final int GAMMA_SPACE_MAX = 1023;
+    public static final boolean ENABLE_GAMMA = false;
 
     // Hybrid Log Gamma constant values
     private static final float R = 0.5f;
@@ -51,6 +52,11 @@ public class BrightnessUtils {
      * @return The corresponding setting value.
      */
     public static final int convertGammaToLinear(int val, int min, int max) {
+        if(!ENABLE_GAMMA){
+            float ratio = (float)val / GAMMA_SPACE_MAX;
+            return min + (int)(ratio * (max - min));
+        }
+        
         final float normalizedVal = MathUtils.norm(0, GAMMA_SPACE_MAX, val);
         final float ret;
         if (normalizedVal <= R) {
@@ -87,6 +93,11 @@ public class BrightnessUtils {
      * @return The corresponding slider value
      */
     public static final int convertLinearToGamma(int val, int min, int max) {
+        if(!ENABLE_GAMMA){
+            float ratio = (float)(val - min)/ (max - min);
+            return (int)(ratio * GAMMA_SPACE_MAX);
+        }
+        

 编译相关模块, 如: SettingsLib, Settings, SystemUI, 重新make install clean 和 make

扩展

  • 编译失败:
    mmm frameworks/base/packages/SystemUI/ -j2
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=9
TARGET_PRODUCT=rk3399
TARGET_BUILD_VARIANT=userdebug
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm64
TARGET_ARCH_VARIANT=armv8-a
TARGET_CPU_VARIANT=cortex-a53
TARGET_2ND_ARCH=arm
TARGET_2ND_ARCH_VARIANT=armv7-a-neon
TARGET_2ND_CPU_VARIANT=cortex-a15
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-4.4.0-142-generic-x86_64-Ubuntu-16.04.6-LTS
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=PI
OUT_DIR=out
============================================
ninja: no work to do.
ninja: no work to do.
out/build-rk3399-_frameworks_base_packages_SystemUI_Android.mk-cleanspec.ninja is missing, regenerating...
out/build-rk3399-_frameworks_base_packages_SystemUI_Android.mk.ninja is missing, regenerating...
ninja: error: 'out/target/common/obj/JAVA_LIBRARIES/metrics-helper-lib_intermediates/classes-header.jar', needed by 'out/target/common/obj/APPS/SystemUISharedLibTests_intermediates/classes-full-debug.jar', missing and no known rule to make it
14:37:27 ninja failed with: exit status 1

#### failed to build some targets (59 seconds) ####

原因: 单编有依赖, 改用 mmma

  • 注意加上LOG打印, 以验证修改生效
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐