Android 9.0 亮度调节的变化(伽马曲线)

简介: Android 9.0 亮度调节的变化(伽马曲线)

平台


 RK3399 + Android 9.0


概述


 众所周知, Android 平台的上层亮度值的设置值范围为[0, 255], 在9.0之前, 亮度调节一直是线性变化, 在9.0开始, 它变成了曲线变化, 如下图:

image.png

        图1-实际亮度值: 11

image.png

        图2-实际亮度值: 15

image.png

        图3-实际亮度值: 33

image.png

        图4-实际亮度值: 105

image.png

        图5-实际亮度值: 255


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

image.png


流程


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


设置

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打印, 以验证修改生效


相关文章
|
1月前
|
Android开发
Android修改媒体音量以及修改屏幕亮度
Android修改媒体音量以及修改屏幕亮度
24 0
|
2月前
|
XML 编解码 Android开发
Android 自定义坐标曲线图(二)
继上一篇文章,本次改进了折线图点击显示提示信息的方式。原来使用popupwindow或dialog,但这种方式控制位置困难,特别是当需要精确显示在点击点上方时。现在,作者通过自定义XML布局实现了更灵活的提示框。
Android 自定义坐标曲线图(二)
|
5月前
|
API Android开发 iOS开发
Android 自定义坐标曲线图
自定义View,使用paint、point、path,画点、点与点连接成线、然后闭合起来就是一个多边形,画坐标,实现坐标曲线图
Android 自定义坐标曲线图
|
8月前
|
Android开发 开发者
Android平台GB28181设备接入端如何调节实时音量?
我们在对接Android平台GB28181设备接入端的时候,有开发者提出这样的疑惑,如何调整设备接入端的实时音量?
|
9月前
|
API Android开发
Android:自定义沿着曲线轨迹移动
实现这样的一个需求,最主要的是曲线的绘制,和如何设置移动的icon轨迹,这两部分攻克之后,这个需求也就完成了。
Android:自定义沿着曲线轨迹移动
|
Java 数据库 Android开发
android4.4 亮度设置
android4.4 亮度设置
125 0
|
前端开发 Android开发
android自定义View绘制天气温度曲线
原文:android自定义View绘制天气温度曲线 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012942410/article/details/50091387 转载请注明出处:http://blog.csdn.net/kaku2013/article/details/50091387 大家好,不久前写了个绘制天气温度曲线功能的demo今天抽空来和大家分享一下。
1860 0
|
前端开发 Android开发
Bezier曲线在Android动画中的应用
Android动画的开发中,为了达到更加酷炫的效果,常常需要自定义运动轨迹,或者绘制花式复杂的曲线,这正是Bezier曲线大显神通的地方,本文将带你了解Bezier曲线在Android开发中的一些应用。
1355 0
|
Android开发 Java 数据格式
Android视频播放器屏幕左侧边随手指上下滑动亮度调节变暗变亮原理实现(2):后续改进
 Android视频播放器屏幕左侧边随手指上下滑动亮度调节变暗变亮原理实现(2):后续改进 附录文章1虽然实现了在屏幕左半边随手指上滑/下滑实现明暗度的调节,但是有一个不完美的地方:当手指在屏幕左半边水平左滑/右滑时候,也一样会触发明暗度的调节。
992 0