From 4b416fe4c93ae35734d28aacb02ed045162c50f9 Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Wed, 12 Aug 2020 17:35:33 -0700 Subject: [PATCH] Implement brightness-aware scrim Bug: 163396794 Test: manual on device Change-Id: I4a87c5876b3e173e5ae25fb35af5681db6538cf0 --- .../systemui/biometrics/UdfpsController.java | 115 +++++++++++++++++- .../systemui/biometrics/UdfpsView.java | 6 +- 2 files changed, 118 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 529b616d2a924..e3126b89fe786 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -17,19 +17,27 @@ package com.android.systemui.biometrics; import android.annotation.SuppressLint; +import android.content.ContentResolver; import android.content.Context; +import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.graphics.Point; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.Handler; import android.os.Looper; +import android.os.PowerManager; +import android.os.UserHandle; +import android.provider.Settings; import android.util.Log; +import android.util.MathUtils; +import android.util.Spline; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.WindowManager; import android.widget.LinearLayout; +import com.android.internal.BrightnessSynchronizer; import com.android.systemui.R; import java.io.FileWriter; @@ -41,16 +49,31 @@ import java.io.IOException; */ class UdfpsController { private static final String TAG = "UdfpsController"; + // Gamma approximation for the sRGB color space. + private static final float DISPLAY_GAMMA = 2.2f; private final FingerprintManager mFingerprintManager; private final WindowManager mWindowManager; + private final ContentResolver mContentResolver; private final Handler mHandler; private final UdfpsView mView; private final WindowManager.LayoutParams mLayoutParams; + // Debugfs path to control the high-brightness mode. private final String mHbmPath; private final String mHbmEnableCommand; private final String mHbmDisableCommand; - + // Brightness in nits in the high-brightness mode. + private final float mHbmNits; + // A spline mapping from the device's backlight value, normalized to the range [0, 1.0], to a + // brightness in nits. + private final Spline mBacklightToNitsSpline; + // A spline mapping from a value in nits to a backlight value of a hypothetical panel whose + // maximum backlight value corresponds to our panel's high-brightness mode. + // The output is normalized to the range [0, 1.0]. + private Spline mNitsToHbmBacklightSpline; + // Default non-HBM backlight value normalized to the range [0, 1.0]. Used as a fallback when the + // actual brightness value cannot be retrieved. + private final float mDefaultBrightness; private boolean mIsOverlayShowing; public class UdfpsOverlayController extends IUdfpsOverlayController.Stub { @@ -96,6 +119,7 @@ class UdfpsController { UdfpsController(Context context) { mFingerprintManager = context.getSystemService(FingerprintManager.class); mWindowManager = context.getSystemService(WindowManager.class); + mContentResolver = context.getContentResolver(); mHandler = new Handler(Looper.getMainLooper()); mLayoutParams = createLayoutParams(context); @@ -109,6 +133,35 @@ class UdfpsController { mHbmEnableCommand = context.getResources().getString(R.string.udfps_hbm_enable_command); mHbmDisableCommand = context.getResources().getString(R.string.udfps_hbm_disable_command); + // This range only consists of the minimum and maximum values, which only cover + // non-high-brightness mode. + float[] nitsRange = toFloatArray(context.getResources().obtainTypedArray( + com.android.internal.R.array.config_screenBrightnessNits)); + + // The last value of this range corresponds to the high-brightness mode. + float[] nitsAutoBrightnessValues = toFloatArray(context.getResources().obtainTypedArray( + com.android.internal.R.array.config_autoBrightnessDisplayValuesNits)); + + mHbmNits = nitsAutoBrightnessValues[nitsAutoBrightnessValues.length - 1]; + float[] hbmNitsRange = {nitsRange[0], mHbmNits}; + + // This range only consists of the minimum and maximum backlight values, which only apply + // in non-high-brightness mode. + float[] normalizedBacklightRange = normalizeBacklightRange( + context.getResources().getIntArray( + com.android.internal.R.array.config_screenBrightnessBacklight)); + + mBacklightToNitsSpline = Spline.createSpline(normalizedBacklightRange, nitsRange); + mNitsToHbmBacklightSpline = Spline.createSpline(hbmNitsRange, normalizedBacklightRange); + mDefaultBrightness = obtainDefaultBrightness(context); + + // TODO(b/160025856): move to the "dump" method. + Log.v(TAG, String.format("ctor | mNitsRange: [%f, %f]", nitsRange[0], nitsRange[1])); + Log.v(TAG, String.format("ctor | mHbmNitsRange: [%f, %f]", hbmNitsRange[0], + hbmNitsRange[1])); + Log.v(TAG, String.format("ctor | mNormalizedBacklightRange: [%f, %f]", + normalizedBacklightRange[0], normalizedBacklightRange[1])); + mFingerprintManager.setUdfpsOverlayController(new UdfpsOverlayController()); mIsOverlayShowing = false; } @@ -138,7 +191,34 @@ class UdfpsController { }); } + // Returns a value in the range of [0, 255]. + private int computeScrimOpacity() { + // Backlight setting can be NaN, -1.0f, and [0.0f, 1.0f]. + float backlightSetting = Settings.System.getFloatForUser(mContentResolver, + Settings.System.SCREEN_BRIGHTNESS_FLOAT, mDefaultBrightness, + UserHandle.USER_CURRENT); + + // Constrain the backlight setting to [0.0f, 1.0f]. + float backlightValue = MathUtils.constrain(backlightSetting, + PowerManager.BRIGHTNESS_MIN, + PowerManager.BRIGHTNESS_MAX); + + // Interpolate the backlight value to nits. + float nits = mBacklightToNitsSpline.interpolate(backlightValue); + + // Interpolate nits to a backlight value for a panel with enabled HBM. + float interpolatedHbmBacklightValue = mNitsToHbmBacklightSpline.interpolate(nits); + + float gammaCorrectedHbmBacklightValue = (float) Math.pow(interpolatedHbmBacklightValue, + 1.0f / DISPLAY_GAMMA); + float scrimOpacity = PowerManager.BRIGHTNESS_MAX - gammaCorrectedHbmBacklightValue; + + // Interpolate the opacity value from [0.0f, 1.0f] to [0, 255]. + return BrightnessSynchronizer.brightnessFloatToInt(scrimOpacity); + } + private void onFingerDown(int x, int y, float minor, float major) { + mView.setScrimAlpha(computeScrimOpacity()); try { FileWriter fw = new FileWriter(mHbmPath); fw.write(mHbmEnableCommand); @@ -174,10 +254,41 @@ class UdfpsController { // TODO(b/152419866): Use the UDFPS window type when it becomes available. WindowManager.LayoutParams.TYPE_BOOT_PROGRESS, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, PixelFormat.TRANSLUCENT); lp.setTitle(TAG); lp.windowAnimations = 0; return lp; } + + private static float obtainDefaultBrightness(Context context) { + PowerManager powerManager = context.getSystemService(PowerManager.class); + if (powerManager == null) { + Log.e(TAG, "PowerManager is unavailable. Can't obtain default brightness."); + return 0f; + } + return MathUtils.constrain(powerManager.getBrightnessConstraint( + PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT), PowerManager.BRIGHTNESS_MIN, + PowerManager.BRIGHTNESS_MAX); + } + + private static float[] toFloatArray(TypedArray array) { + final int n = array.length(); + float[] vals = new float[n]; + for (int i = 0; i < n; i++) { + vals[i] = array.getFloat(i, PowerManager.BRIGHTNESS_OFF_FLOAT); + } + array.recycle(); + return vals; + } + + private static float[] normalizeBacklightRange(int[] backlight) { + final int n = backlight.length; + float[] normalizedBacklight = new float[n]; + for (int i = 0; i < n; i++) { + normalizedBacklight[i] = BrightnessSynchronizer.brightnessIntToFloat(backlight[i]); + } + return normalizedBacklight; + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java index 8190550a74fc0..d4e86d5dd234c 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java @@ -79,7 +79,7 @@ public class UdfpsView extends View { mScrimRect = new Rect(); mScrimPaint = new Paint(0 /* flags */); - mScrimPaint.setARGB(110 /* a */, 0 /* r */, 0 /* g */, 0 /* b */); + mScrimPaint.setColor(Color.BLACK); mSensorRect = new RectF(); mSensorPaint = new Paint(0 /* flags */); @@ -136,6 +136,10 @@ public class UdfpsView extends View { && y < (mSensorY + mSensorRadius * mSensorTouchAreaCoefficient); } + void setScrimAlpha(int alpha) { + mScrimPaint.setAlpha(alpha); + } + boolean isFingerDown() { return mIsFingerDown; }