diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 36673cd66ca2f..4de4880b7c171 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -655,6 +655,34 @@ public final class DisplayManager { mGlobal.setBrightnessConfigurationForUser(c, userId, packageName); } + /** + * Temporarily sets the brightness of the display. + *

+ * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. + *

+ * + * @param brightness The brightness value from 0 to 255. + * + * @hide Requires signature permission. + */ + public void setTemporaryBrightness(int brightness) { + mGlobal.setTemporaryBrightness(brightness); + } + + /** + * Temporarily sets the auto brightness adjustment factor. + *

+ * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. + *

+ * + * @param adjustment The adjustment factor from -1.0 to 1.0. + * + * @hide Requires signature permission. + */ + public void setTemporaryAutoBrightnessAdjustment(float adjustment) { + mGlobal.setTemporaryAutoBrightnessAdjustment(adjustment); + } + /** * Listens for changes in available display devices. */ diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 9c851f1fd1066..2d5f5e0414868 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -489,6 +489,42 @@ public final class DisplayManagerGlobal { } } + /** + * Temporarily sets the brightness of the display. + *

+ * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. + *

+ * + * @param brightness The brightness value from 0 to 255. + * + * @hide Requires signature permission. + */ + public void setTemporaryBrightness(int brightness) { + try { + mDm.setTemporaryBrightness(brightness); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** + * Temporarily sets the auto brightness adjustment factor. + *

+ * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. + *

+ * + * @param adjustment The adjustment factor from -1.0 to 1.0. + * + * @hide Requires signature permission. + */ + public void setTemporaryAutoBrightnessAdjustment(float adjustment) { + try { + mDm.setTemporaryAutoBrightnessAdjustment(adjustment); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub { @Override public void onDisplayEvent(int displayId, int event) { diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index 078958ad881a5..1cfad4f0168f4 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -214,23 +214,12 @@ public abstract class DisplayManagerInternal { // nearby, turning it off temporarily until the object is moved away. public boolean useProximitySensor; - // The desired screen brightness in the range 0 (minimum / off) to 255 (brightest). - // The display power controller may choose to clamp the brightness. - // When auto-brightness is enabled, this field should specify a nominal default - // value to use while waiting for the light sensor to report enough data. - public int screenBrightness; + // An override of the screen brightness. Set to -1 is used if there's no override. + public int screenBrightnessOverride; - // The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter). - public float screenAutoBrightnessAdjustment; - - // Set to true if screenBrightness and screenAutoBrightnessAdjustment were both - // set by the user as opposed to being programmatically controlled by apps. - public boolean brightnessSetByUser; - - // Set to true if screenBrightness or screenAutoBrightnessAdjustment are being set - // temporarily. This is typically set while the user has their finger on the brightness - // control, before they've selected the final brightness value. - public boolean brightnessIsTemporary; + // An override of the screen auto-brightness adjustment factor in the range -1 (dimmer) to + // 1 (brighter). Set to Float.NaN if there's no override. + public float screenAutoBrightnessAdjustmentOverride; // If true, enables automatic brightness control. public boolean useAutoBrightness; @@ -262,10 +251,10 @@ public abstract class DisplayManagerInternal { public DisplayPowerRequest() { policy = POLICY_BRIGHT; useProximitySensor = false; - screenBrightness = PowerManager.BRIGHTNESS_ON; - screenAutoBrightnessAdjustment = 0.0f; - screenLowPowerBrightnessFactor = 0.5f; + screenBrightnessOverride = -1; useAutoBrightness = false; + screenAutoBrightnessAdjustmentOverride = Float.NaN; + screenLowPowerBrightnessFactor = 0.5f; blockScreenOn = false; dozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT; dozeScreenState = Display.STATE_UNKNOWN; @@ -286,12 +275,10 @@ public abstract class DisplayManagerInternal { public void copyFrom(DisplayPowerRequest other) { policy = other.policy; useProximitySensor = other.useProximitySensor; - screenBrightness = other.screenBrightness; - screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment; - screenLowPowerBrightnessFactor = other.screenLowPowerBrightnessFactor; - brightnessSetByUser = other.brightnessSetByUser; - brightnessIsTemporary = other.brightnessIsTemporary; + screenBrightnessOverride = other.screenBrightnessOverride; useAutoBrightness = other.useAutoBrightness; + screenAutoBrightnessAdjustmentOverride = other.screenAutoBrightnessAdjustmentOverride; + screenLowPowerBrightnessFactor = other.screenLowPowerBrightnessFactor; blockScreenOn = other.blockScreenOn; lowPowerMode = other.lowPowerMode; boostScreenBrightness = other.boostScreenBrightness; @@ -309,13 +296,12 @@ public abstract class DisplayManagerInternal { return other != null && policy == other.policy && useProximitySensor == other.useProximitySensor - && screenBrightness == other.screenBrightness - && screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment + && screenBrightnessOverride == other.screenBrightnessOverride + && useAutoBrightness == other.useAutoBrightness + && floatEquals(screenAutoBrightnessAdjustmentOverride, + other.screenAutoBrightnessAdjustmentOverride) && screenLowPowerBrightnessFactor == other.screenLowPowerBrightnessFactor - && brightnessSetByUser == other.brightnessSetByUser - && brightnessIsTemporary == other.brightnessIsTemporary - && useAutoBrightness == other.useAutoBrightness && blockScreenOn == other.blockScreenOn && lowPowerMode == other.lowPowerMode && boostScreenBrightness == other.boostScreenBrightness @@ -323,6 +309,10 @@ public abstract class DisplayManagerInternal { && dozeScreenState == other.dozeScreenState; } + private boolean floatEquals(float f1, float f2) { + return f1 == f2 || Float.isNaN(f1) && Float.isNaN(f2); + } + @Override public int hashCode() { return 0; // don't care @@ -332,12 +322,11 @@ public abstract class DisplayManagerInternal { public String toString() { return "policy=" + policyToString(policy) + ", useProximitySensor=" + useProximitySensor - + ", screenBrightness=" + screenBrightness - + ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment - + ", screenLowPowerBrightnessFactor=" + screenLowPowerBrightnessFactor - + ", brightnessSetByUser=" + brightnessSetByUser - + ", brightnessIsTemporary=" + brightnessIsTemporary + + ", screenBrightnessOverride=" + screenBrightnessOverride + ", useAutoBrightness=" + useAutoBrightness + + ", screenAutoBrightnessAdjustmentOverride=" + + screenAutoBrightnessAdjustmentOverride + + ", screenLowPowerBrightnessFactor=" + screenLowPowerBrightnessFactor + ", blockScreenOn=" + blockScreenOn + ", lowPowerMode=" + lowPowerMode + ", boostScreenBrightness=" + boostScreenBrightness diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl index 5b7b32fe52012..13599cfa0b7d5 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -92,4 +92,10 @@ interface IDisplayManager { // the same as the calling user. void setBrightnessConfigurationForUser(in BrightnessConfiguration c, int userId, String packageName); + + // Temporarily sets the display brightness. + void setTemporaryBrightness(int brightness); + + // Temporarily sets the auto brightness adjustment factor. + void setTemporaryAutoBrightnessAdjustment(float adjustment); } diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index 75f7c1f58ab94..1681f11fa5263 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -63,11 +63,6 @@ interface IPowerManager // --- deprecated --- boolean isScreenBrightnessBoosted(); - // temporarily overrides the screen brightness settings to allow the user to - // see the effect of a settings change without applying it immediately - void setTemporaryScreenBrightnessSettingOverride(int brightness); - void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float adj); - // sets the attention light (used by phone app only) void setAttentionLight(boolean on, int color); } diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 61172e11fec26..3d17ffb7329f1 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -1001,24 +1001,6 @@ public final class PowerManager { return false; } - /** - * Sets the brightness of the backlights (screen, keyboard, button). - *

- * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. - *

- * - * @param brightness The brightness value from 0 to 255. - * - * @hide Requires signature permission. - */ - public void setBacklightBrightness(int brightness) { - try { - mService.setTemporaryScreenBrightnessSettingOverride(brightness); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - /** * Returns true if the specified wake lock level is supported. * diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f1a9bd480a732..ea791a5da5ad0 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3000,6 +3000,11 @@ + + + diff --git a/core/tests/coretests/src/android/os/BrightnessLimit.java b/core/tests/coretests/src/android/os/BrightnessLimit.java index 43cd373ef8505..fabcf3d920a94 100644 --- a/core/tests/coretests/src/android/os/BrightnessLimit.java +++ b/core/tests/coretests/src/android/os/BrightnessLimit.java @@ -16,12 +16,9 @@ package android.os; -import android.os.IPowerManager; - import android.app.Activity; +import android.hardware.display.DisplayManager; import android.os.Bundle; -import android.os.RemoteException; -import android.os.ServiceManager; import android.provider.Settings; import android.view.View; import android.view.View.OnClickListener; @@ -37,23 +34,16 @@ public class BrightnessLimit extends Activity implements OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + setContentView(R.layout.brightness_limit); - + Button b = findViewById(R.id.go); b.setOnClickListener(this); } public void onClick(View v) { - IPowerManager power = IPowerManager.Stub.asInterface( - ServiceManager.getService("power")); - if (power != null) { - try { - power.setTemporaryScreenBrightnessSettingOverride(0); - } catch (RemoteException darn) { - - } - } + DisplayManager dm = getSystemService(DisplayManager.class); + dm.setTemporaryBrightness(0); Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, 0); } } diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java index 9893c161fec86..0d250b825d97c 100644 --- a/core/tests/coretests/src/android/os/PowerManagerTest.java +++ b/core/tests/coretests/src/android/os/PowerManagerTest.java @@ -21,9 +21,9 @@ import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; public class PowerManagerTest extends AndroidTestCase { - + private PowerManager mPm; - + /** * Setup any common data for the upcoming tests. */ @@ -32,10 +32,10 @@ public class PowerManagerTest extends AndroidTestCase { super.setUp(); mPm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); } - + /** * Confirm that the setup is good. - * + * * @throws Exception */ @SmallTest @@ -45,7 +45,7 @@ public class PowerManagerTest extends AndroidTestCase { /** * Confirm that we can create functional wakelocks. - * + * * @throws Exception */ @SmallTest @@ -61,22 +61,19 @@ public class PowerManagerTest extends AndroidTestCase { wl = mPm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PARTIAL_WAKE_LOCK"); doTestWakeLock(wl); - - doTestSetBacklightBrightness(); - // TODO: Some sort of functional test (maybe not in the unit test here?) + // TODO: Some sort of functional test (maybe not in the unit test here?) // that confirms that things are really happening e.g. screen power, keyboard power. } - + /** * Confirm that we can't create dysfunctional wakelocks. - * + * * @throws Exception */ @SmallTest public void testBadNewWakeLock() throws Exception { - - final int badFlags = PowerManager.SCREEN_BRIGHT_WAKE_LOCK + final int badFlags = PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.SCREEN_DIM_WAKE_LOCK; // wrap in try because we want the error here try { @@ -86,10 +83,10 @@ public class PowerManagerTest extends AndroidTestCase { } fail("Bad WakeLock flag was not caught."); } - + /** * Apply a few tests to a wakelock to make sure it's healthy. - * + * * @param wl The wakelock to be tested. */ private void doTestWakeLock(PowerManager.WakeLock wl) { @@ -98,7 +95,7 @@ public class PowerManagerTest extends AndroidTestCase { assertTrue(wl.isHeld()); wl.release(); assertFalse(wl.isHeld()); - + // Try ref-counted acquire/release wl.setReferenceCounted(true); wl.acquire(); @@ -109,7 +106,7 @@ public class PowerManagerTest extends AndroidTestCase { assertTrue(wl.isHeld()); wl.release(); assertFalse(wl.isHeld()); - + // Try non-ref-counted wl.setReferenceCounted(false); wl.acquire(); @@ -118,24 +115,7 @@ public class PowerManagerTest extends AndroidTestCase { assertTrue(wl.isHeld()); wl.release(); assertFalse(wl.isHeld()); - + // TODO: Threaded test (needs handler) to make sure timed wakelocks work too } - - - /** - * Test that calling {@link android.os.IHardwareService#setBacklights(int)} requires - * permissions. - *

Tests permission: - * {@link android.Manifest.permission#DEVICE_POWER} - */ - private void doTestSetBacklightBrightness() { - try { - mPm.setBacklightBrightness(0); - fail("setBacklights did not throw SecurityException as expected"); - } catch (SecurityException e) { - // expected - } - } - } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java index cfd33a19baf90..91957e1ff05cd 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java @@ -30,6 +30,7 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; +import android.hardware.display.DisplayManager; import android.icu.util.ULocale; import android.location.LocationManager; import android.media.AudioManager; @@ -306,15 +307,7 @@ public class SettingsHelper { } private void setBrightness(int brightness) { - try { - IPowerManager power = IPowerManager.Stub.asInterface( - ServiceManager.getService("power")); - if (power != null) { - power.setTemporaryScreenBrightnessSettingOverride(brightness); - } - } catch (RemoteException doe) { - - } + mContext.getSystemService(DisplayManager.class).setTemporaryBrightness(brightness); } /* package */ byte[] getLocaleData() { diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 0b6e11bf86384..42b7213e84f05 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -72,6 +72,7 @@ + diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java index d3f997a045003..3db30fcbbe6b2 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java @@ -16,9 +16,11 @@ package com.android.systemui.settings; +import android.animation.ValueAnimator; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; +import android.hardware.display.DisplayManager; import android.net.Uri; import android.os.AsyncTask; import android.os.Handler; @@ -45,11 +47,7 @@ public class BrightnessController implements ToggleSlider.Listener { private static final String TAG = "StatusBar.BrightnessController"; private static final boolean SHOW_AUTOMATIC_ICON = false; - /** - * {@link android.provider.Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ} uses the range [-1, 1]. - * Using this factor, it is converted to [0, BRIGHTNESS_ADJ_RESOLUTION] for the SeekBar. - */ - private static final float BRIGHTNESS_ADJ_RESOLUTION = 2048; + private static final int SLIDER_ANIMATION_DURATION = 3000; private static final int MSG_UPDATE_ICON = 0; private static final int MSG_UPDATE_SLIDER = 1; @@ -67,7 +65,7 @@ public class BrightnessController implements ToggleSlider.Listener { private final ImageView mIcon; private final ToggleSlider mControl; private final boolean mAutomaticAvailable; - private final IPowerManager mPower; + private final DisplayManager mDisplayManager; private final CurrentUserTracker mUserTracker; private final IVrManager mVrManager; @@ -81,6 +79,9 @@ public class BrightnessController implements ToggleSlider.Listener { private volatile boolean mIsVrModeEnabled; private boolean mListening; private boolean mExternalChange; + private boolean mControlInitialized; + + private ValueAnimator mSliderAnimator; public interface BrightnessStateChangeCallback { public void onBrightnessLevelChanged(); @@ -95,8 +96,6 @@ public class BrightnessController implements ToggleSlider.Listener { Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS); private final Uri BRIGHTNESS_FOR_VR_URI = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_VR); - private final Uri BRIGHTNESS_ADJ_URI = - Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ); public BrightnessObserver(Handler handler) { super(handler); @@ -114,12 +113,10 @@ public class BrightnessController implements ToggleSlider.Listener { if (BRIGHTNESS_MODE_URI.equals(uri)) { mBackgroundHandler.post(mUpdateModeRunnable); mBackgroundHandler.post(mUpdateSliderRunnable); - } else if (BRIGHTNESS_URI.equals(uri) && !mAutomatic) { + } else if (BRIGHTNESS_URI.equals(uri)) { mBackgroundHandler.post(mUpdateSliderRunnable); } else if (BRIGHTNESS_FOR_VR_URI.equals(uri)) { mBackgroundHandler.post(mUpdateSliderRunnable); - } else if (BRIGHTNESS_ADJ_URI.equals(uri) && mAutomatic) { - mBackgroundHandler.post(mUpdateSliderRunnable); } else { mBackgroundHandler.post(mUpdateModeRunnable); mBackgroundHandler.post(mUpdateSliderRunnable); @@ -141,9 +138,6 @@ public class BrightnessController implements ToggleSlider.Listener { cr.registerContentObserver( BRIGHTNESS_FOR_VR_URI, false, this, UserHandle.USER_ALL); - cr.registerContentObserver( - BRIGHTNESS_ADJ_URI, - false, this, UserHandle.USER_ALL); } public void stopObserving() { @@ -214,12 +208,6 @@ public class BrightnessController implements ToggleSlider.Listener { mHandler.obtainMessage(MSG_UPDATE_SLIDER, mMaximumBacklightForVr - mMinimumBacklightForVr, value - mMinimumBacklightForVr).sendToTarget(); - } else if (mAutomatic) { - float value = Settings.System.getFloatForUser(mContext.getContentResolver(), - Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0, - UserHandle.USER_CURRENT); - mHandler.obtainMessage(MSG_UPDATE_SLIDER, (int) BRIGHTNESS_ADJ_RESOLUTION, - (int) ((value + 1) * BRIGHTNESS_ADJ_RESOLUTION / 2f)).sendToTarget(); } else { int value; value = Settings.System.getIntForUser(mContext.getContentResolver(), @@ -250,7 +238,7 @@ public class BrightnessController implements ToggleSlider.Listener { break; case MSG_UPDATE_SLIDER: mControl.setMax(msg.arg1); - mControl.setValue(msg.arg2); + animateSliderTo(msg.arg2); break; case MSG_SET_CHECKED: mControl.setChecked(msg.arg1 != 0); @@ -295,8 +283,7 @@ public class BrightnessController implements ToggleSlider.Listener { mAutomaticAvailable = context.getResources().getBoolean( com.android.internal.R.bool.config_automatic_brightness_available); - mPower = IPowerManager.Stub.asInterface(ServiceManager.getService( - Context.POWER_SERVICE)); + mDisplayManager = context.getSystemService(DisplayManager.class); mVrManager = IVrManager.Stub.asInterface(ServiceManager.getService( Context.VR_SERVICE)); } @@ -356,6 +343,10 @@ public class BrightnessController implements ToggleSlider.Listener { updateIcon(mAutomatic); if (mExternalChange) return; + if (mSliderAnimator != null) { + mSliderAnimator.cancel(); + } + if (mIsVrModeEnabled) { final int val = value + mMinimumBacklightForVr; if (stopTracking) { @@ -371,7 +362,7 @@ public class BrightnessController implements ToggleSlider.Listener { } }); } - } else if (!mAutomatic) { + } else { final int val = value + mMinimumBacklight; if (stopTracking) { MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS, val); @@ -386,21 +377,6 @@ public class BrightnessController implements ToggleSlider.Listener { } }); } - } else { - final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1; - if (stopTracking) { - MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS_AUTO, value); - } - setBrightnessAdj(adj); - if (!tracking) { - AsyncTask.execute(new Runnable() { - public void run() { - Settings.System.putFloatForUser(mContext.getContentResolver(), - Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adj, - UserHandle.USER_CURRENT); - } - }); - } } for (BrightnessStateChangeCallback cb : mChangeCallbacks) { @@ -415,17 +391,11 @@ public class BrightnessController implements ToggleSlider.Listener { } private void setBrightness(int brightness) { - try { - mPower.setTemporaryScreenBrightnessSettingOverride(brightness); - } catch (RemoteException ex) { - } + mDisplayManager.setTemporaryBrightness(brightness); } private void setBrightnessAdj(float adj) { - try { - mPower.setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(adj); - } catch (RemoteException ex) { - } + mDisplayManager.setTemporaryAutoBrightnessAdjustment(adj); } private void updateIcon(boolean automatic) { @@ -442,4 +412,23 @@ public class BrightnessController implements ToggleSlider.Listener { mBackgroundHandler.post(mUpdateSliderRunnable); } } + + private void animateSliderTo(int target) { + if (!mControlInitialized) { + // Don't animate the first value since it's default state isn't meaningful to users. + mControl.setValue(target); + mControlInitialized = true; + } + if (mSliderAnimator != null && mSliderAnimator.isStarted()) { + mSliderAnimator.cancel(); + } + mSliderAnimator = ValueAnimator.ofInt(mControl.getValue(), target); + mSliderAnimator.addUpdateListener((ValueAnimator animation) -> { + mExternalChange = true; + mControl.setValue((int)animation.getAnimatedValue()); + mExternalChange = false; + }); + mSliderAnimator.setDuration(SLIDER_ANIMATION_DURATION); + mSliderAnimator.start(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java index 62abf3d6c3e21..135f89d3f3431 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java +++ b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java @@ -28,4 +28,5 @@ public interface ToggleSlider { default boolean isChecked() { return false; } void setMax(int max); void setValue(int value); + int getValue(); } diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSliderView.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSliderView.java index 5b234e9c55768..07b9ec27629f5 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSliderView.java +++ b/packages/SystemUI/src/com/android/systemui/settings/ToggleSliderView.java @@ -125,6 +125,11 @@ public class ToggleSliderView extends RelativeLayout implements ToggleSlider { } } + @Override + public int getValue() { + return mSlider.getProgress(); + } + @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (mMirror != null) { diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index 6c5bfc7933303..e445d27151965 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -25,6 +25,7 @@ import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.display.BrightnessConfiguration; +import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -57,8 +58,16 @@ class AutomaticBrightnessController { // the user is satisfied with the result before storing the sample. private static final int BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS = 10000; + // Timeout after which we remove the effects any user interactions might've had on the + // brightness mapping. This timeout doesn't start until we transition to a non-interactive + // display policy so that we don't reset while users are using their devices, but also so that + // we don't erroneously keep the short-term model if the device is dozing but the display is + // fully on. + private static final int SHORT_TERM_MODEL_TIMEOUT_MILLIS = 30000; + private static final int MSG_UPDATE_AMBIENT_LUX = 1; private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2; + private static final int MSG_RESET_SHORT_TERM_MODEL = 3; // Length of the ambient light horizon used to calculate the long term estimate of ambient // light. @@ -173,8 +182,9 @@ class AutomaticBrightnessController { // The last screen auto-brightness gamma. (For printing in dump() only.) private float mLastScreenAutoBrightnessGamma = 1.0f; - // Are we going to adjust brightness while dozing. - private boolean mDozing; + // The current display policy. This is useful, for example, for knowing when we're dozing, + // where the light sensor may not be available. + private int mDisplayPolicy = DisplayPowerRequest.POLICY_OFF; // True if we are collecting a brightness adjustment sample, along with some data // for the initial state of the sample. @@ -221,31 +231,72 @@ class AutomaticBrightnessController { } public int getAutomaticScreenBrightness() { - if (mDozing) { + if (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE) { return (int) (mScreenAutoBrightness * mDozeScaleFactor); } return mScreenAutoBrightness; } public void configure(boolean enable, @Nullable BrightnessConfiguration configuration, - float adjustment, boolean dozing, boolean userInitiatedChange) { + float brightness, float adjustment, int displayPolicy, boolean userInitiatedChange) { // 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 dozing = (displayPolicy == DisplayPowerRequest.POLICY_DOZE); boolean changed = setBrightnessConfiguration(configuration); - changed |= setLightSensorEnabled(enable && !dozing); - if (enable && !dozing && userInitiatedChange) { + changed |= setDisplayPolicy(displayPolicy); + if (userInitiatedChange && enable && !dozing) { + // Update the current brightness value. + changed |= setScreenBrightnessByUser(brightness); prepareBrightnessAdjustmentSample(); } changed |= setScreenAutoBrightnessAdjustment(adjustment); + changed |= setLightSensorEnabled(enable && !dozing); if (changed) { updateAutoBrightness(false /*sendUpdate*/); } } + private boolean setDisplayPolicy(int policy) { + if (mDisplayPolicy == policy) { + return false; + } + final int oldPolicy = mDisplayPolicy; + mDisplayPolicy = policy; + if (DEBUG) { + Slog.d(TAG, "Display policy transitioning from " + mDisplayPolicy + " to " + policy); + } + if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) { + mHandler.sendEmptyMessageDelayed(MSG_RESET_SHORT_TERM_MODEL, + SHORT_TERM_MODEL_TIMEOUT_MILLIS); + } else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) { + mHandler.removeMessages(MSG_RESET_SHORT_TERM_MODEL); + } + return true; + } + + private static boolean isInteractivePolicy(int policy) { + return policy == DisplayPowerRequest.POLICY_BRIGHT + || policy == DisplayPowerRequest.POLICY_DIM + || policy == DisplayPowerRequest.POLICY_VR; + } + + private boolean setScreenBrightnessByUser(float brightness) { + if (!mAmbientLuxValid) { + // If we don't have a valid ambient lux then we don't have a valid brightness anyways, + // and we can't use this data to add a new control point to the short-term model. + return false; + } + mBrightnessMapper.addUserDataPoint(mAmbientLux, brightness); + return true; + } + + private void resetShortTermModel() { + mBrightnessMapper.clearUserDataPoints(); + } + public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) { return mBrightnessMapper.setBrightnessConfiguration(configuration); } @@ -280,7 +331,7 @@ class AutomaticBrightnessController { pw.println(" mScreenAutoBrightnessAdjustmentMaxGamma=" + mScreenAutoBrightnessAdjustmentMaxGamma); pw.println(" mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma); - pw.println(" mDozing=" + mDozing); + pw.println(" mDisplayPolicy=" + mDisplayPolicy); pw.println(); mBrightnessMapper.dump(pw); @@ -364,6 +415,10 @@ class AutomaticBrightnessController { if (DEBUG) { Slog.d(TAG, "setAmbientLux(" + lux + ")"); } + if (lux < 0) { + Slog.w(TAG, "Ambient lux was negative, ignoring and setting to 0."); + lux = 0; + } mAmbientLux = lux; mBrighteningLuxThreshold = mDynamicHysteresis.getBrighteningThreshold(lux); mDarkeningLuxThreshold = mDynamicHysteresis.getDarkeningThreshold(lux); @@ -647,6 +702,10 @@ class AutomaticBrightnessController { case MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE: collectBrightnessAdjustmentSample(); break; + + case MSG_RESET_SHORT_TERM_MODEL: + resetShortTermModel(); + break; } } } diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java index ac0e1b5c35502..436ebff0ad86e 100644 --- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java +++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java @@ -30,6 +30,7 @@ import com.android.internal.util.Preconditions; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; +import java.util.Arrays; /** * A utility to map from an ambient brightness to a display's "backlight" brightness based on the @@ -42,6 +43,9 @@ public abstract class BrightnessMappingStrategy { private static final String TAG = "BrightnessMappingStrategy"; private static final boolean DEBUG = false; + private static final float LUX_GRAD_SMOOTHING = 0.25f; + private static final float MAX_GRAD = 1.0f; + @Nullable public static BrightnessMappingStrategy create(Resources resources) { float[] luxLevels = getLuxLevels(resources.getIntArray( @@ -169,11 +173,28 @@ public abstract class BrightnessMappingStrategy { public abstract float getBrightness(float lux); /** - * Gets the display's brightness in nits for the given backlight value. + * Converts the provided backlight value to nits if possible. * * Returns -1.0f if there's no available mapping for the backlight to nits. */ - public abstract float getNits(int backlight); + public abstract float convertToNits(int backlight); + + /** + * Adds a user interaction data point to the brightness mapping. + * + * Currently, we only keep track of one of these at a time to constrain what can happen to the + * curve. + */ + public abstract void addUserDataPoint(float lux, float brightness); + + /** + * Removes any short term adjustments made to the curve from user interactions. + * + * Note that this does *not* reset the mapping to its initial state, any brightness + * configurations that have been applied will continue to be in effect. This solely removes the + * effects of user interactions on the model. + */ + public abstract void clearUserDataPoints(); public abstract void dump(PrintWriter pw); @@ -183,6 +204,112 @@ public abstract class BrightnessMappingStrategy { return (float) brightness / PowerManager.BRIGHTNESS_ON; } + private static Spline createSpline(float[] x, float[] y) { + Spline spline = Spline.createSpline(x, y); + if (DEBUG) { + Slog.d(TAG, "Spline: " + spline); + for (float v = 1f; v < x[x.length - 1] * 1.25f; v *= 1.25f) { + Slog.d(TAG, String.format(" %7.1f: %7.1f", v, spline.interpolate(v))); + } + } + return spline; + } + + private static Pair insertControlPoint( + float[] luxLevels, float[] brightnessLevels, float lux, float brightness) { + if (DEBUG) { + Slog.d(TAG, "Inserting new control point at (" + lux + ", " + brightness + ")"); + } + final int idx = findInsertionPoint(luxLevels, lux); + final float[] newLuxLevels; + final float[] newBrightnessLevels; + if (idx == luxLevels.length) { + newLuxLevels = Arrays.copyOf(luxLevels, luxLevels.length + 1); + newBrightnessLevels = Arrays.copyOf(brightnessLevels, brightnessLevels.length + 1); + newLuxLevels[idx] = lux; + newBrightnessLevels[idx] = brightness; + } else if (luxLevels[idx] == lux) { + newLuxLevels = Arrays.copyOf(luxLevels, luxLevels.length); + newBrightnessLevels = Arrays.copyOf(brightnessLevels, brightnessLevels.length); + newBrightnessLevels[idx] = brightness; + } else { + newLuxLevels = Arrays.copyOf(luxLevels, luxLevels.length + 1); + System.arraycopy(newLuxLevels, idx, newLuxLevels, idx+1, luxLevels.length - idx); + newLuxLevels[idx] = lux; + newBrightnessLevels = Arrays.copyOf(brightnessLevels, brightnessLevels.length + 1); + System.arraycopy(newBrightnessLevels, idx, newBrightnessLevels, idx+1, + brightnessLevels.length - idx); + newBrightnessLevels[idx] = brightness; + } + smoothCurve(newLuxLevels, newBrightnessLevels, idx); + return Pair.create(newLuxLevels, newBrightnessLevels); + } + + /** + * Returns the index of the first value that's less than or equal to {@code val}. + * + * This assumes that {@code arr} is sorted. If all values in {@code arr} are greater + * than val, then it will return the length of arr as the insertion point. + */ + private static int findInsertionPoint(float[] arr, float val) { + for (int i = 0; i < arr.length; i++) { + if (val <= arr[i]) { + return i; + } + } + return arr.length; + } + + private static void smoothCurve(float[] lux, float[] brightness, int idx) { + if (DEBUG) { + Slog.d(TAG, "smoothCurve(lux=" + Arrays.toString(lux) + + ", brightness=" + Arrays.toString(brightness) + + ", idx=" + idx + ")"); + } + float prevLux = lux[idx]; + float prevBrightness = brightness[idx]; + // Smooth curve for data points above the newly introduced point + for (int i = idx+1; i < lux.length; i++) { + float currLux = lux[i]; + float currBrightness = brightness[i]; + float maxBrightness = prevBrightness * permissibleRatio(currLux, prevLux); + float newBrightness = MathUtils.constrain( + currBrightness, prevBrightness, maxBrightness); + if (newBrightness == currBrightness) { + break; + } + prevLux = currLux; + prevBrightness = newBrightness; + brightness[i] = newBrightness; + } + + // Smooth curve for data points below the newly introduced point + prevLux = lux[idx]; + prevBrightness = brightness[idx]; + for (int i = idx-1; i >= 0; i--) { + float currLux = lux[i]; + float currBrightness = brightness[i]; + float minBrightness = prevBrightness * permissibleRatio(currLux, prevLux); + float newBrightness = MathUtils.constrain( + currBrightness, minBrightness, prevBrightness); + if (newBrightness == currBrightness) { + break; + } + prevLux = currLux; + prevBrightness = newBrightness; + brightness[i] = newBrightness; + } + if (DEBUG) { + Slog.d(TAG, "Smoothed Curve: lux=" + Arrays.toString(lux) + + ", brightness=" + Arrays.toString(brightness)); + } + } + + private static float permissibleRatio(float currLux, float prevLux) { + return MathUtils.exp(MAX_GRAD + * (MathUtils.log(currLux + LUX_GRAD_SMOOTHING) + - MathUtils.log(prevLux + LUX_GRAD_SMOOTHING))); + } /** * A {@link BrightnessMappingStrategy} that maps from ambient room brightness directly to the @@ -192,7 +319,14 @@ public abstract class BrightnessMappingStrategy { * configurations that are set are just ignored. */ private static class SimpleMappingStrategy extends BrightnessMappingStrategy { - private final Spline mSpline; + // Lux control points + private final float[] mLux; + // Brightness control points normalized to [0, 1] + private final float[] mBrightness; + + private Spline mSpline; + private float mUserLux; + private float mUserBrightness; public SimpleMappingStrategy(float[] lux, int[] brightness) { Preconditions.checkArgument(lux.length != 0 && brightness.length != 0, @@ -204,20 +338,16 @@ public abstract class BrightnessMappingStrategy { 0, Integer.MAX_VALUE, "brightness"); final int N = brightness.length; - float[] x = new float[N]; - float[] y = new float[N]; + mLux = new float[N]; + mBrightness = new float[N]; for (int i = 0; i < N; i++) { - x[i] = lux[i]; - y[i] = normalizeAbsoluteBrightness(brightness[i]); + mLux[i] = lux[i]; + mBrightness[i] = normalizeAbsoluteBrightness(brightness[i]); } - mSpline = Spline.createSpline(x, y); - if (DEBUG) { - Slog.d(TAG, "Auto-brightness spline: " + mSpline); - for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) { - Slog.d(TAG, String.format(" %7.1f: %7.1f", v, mSpline.interpolate(v))); - } - } + mSpline = createSpline(mLux, mBrightness); + mUserLux = -1; + mUserBrightness = -1; } @Override @@ -231,14 +361,36 @@ public abstract class BrightnessMappingStrategy { } @Override - public float getNits(int backlight) { + public float convertToNits(int backlight) { return -1.0f; } + @Override + public void addUserDataPoint(float lux, float brightness) { + if (DEBUG){ + Slog.d(TAG, "addUserDataPoint(lux=" + lux + ", brightness=" + brightness + ")"); + } + Pair curve = insertControlPoint(mLux, mBrightness, lux, brightness); + mSpline = createSpline(curve.first, curve.second); + mUserLux = lux; + mUserBrightness = brightness; + } + + @Override + public void clearUserDataPoints() { + if (mUserLux != -1) { + mSpline = createSpline(mLux, mBrightness); + mUserLux = -1; + mUserBrightness = -1; + } + } + @Override public void dump(PrintWriter pw) { pw.println("SimpleMappingStrategy"); pw.println(" mSpline=" + mSpline); + pw.println(" mUserLux=" + mUserLux); + pw.println(" mUserBrightness=" + mUserBrightness); } } @@ -261,13 +413,16 @@ public abstract class BrightnessMappingStrategy { // [0, 1.0]. private final Spline mNitsToBacklightSpline; - // 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; - // The default brightness configuration. private final BrightnessConfiguration mDefaultConfig; + // A spline mapping from the device's backlight value, normalized to the range [0, 1.0], to + // a brightness in nits. + private Spline mBacklightToNitsSpline; + + private float mUserLux; + private float mUserBrightness; + public PhysicalMappingStrategy(BrightnessConfiguration config, float[] nits, int[] backlight) { Preconditions.checkArgument(nits.length != 0 && backlight.length != 0, @@ -279,6 +434,9 @@ public abstract class BrightnessMappingStrategy { Preconditions.checkArrayElementsInRange(backlight, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON, "backlight"); + mUserLux = -1; + mUserBrightness = -1; + // Setup the backlight spline final int N = nits.length; float[] normalizedBacklight = new float[N]; @@ -286,15 +444,8 @@ public abstract class BrightnessMappingStrategy { normalizedBacklight[i] = normalizeAbsoluteBrightness(backlight[i]); } - mNitsToBacklightSpline = Spline.createSpline(nits, normalizedBacklight); - mBacklightToNitsSpline = Spline.createSpline(normalizedBacklight, nits); - if (DEBUG) { - Slog.d(TAG, "Backlight spline: " + mNitsToBacklightSpline); - for (float v = 1f; v < nits[nits.length - 1] * 1.25f; v *= 1.25f) { - Slog.d(TAG, String.format( - " %7.1f: %7.1f", v, mNitsToBacklightSpline.interpolate(v))); - } - } + mNitsToBacklightSpline = createSpline(nits, normalizedBacklight); + mBacklightToNitsSpline = createSpline(normalizedBacklight, nits); mDefaultConfig = config; setBrightnessConfiguration(config); @@ -306,42 +457,59 @@ public abstract class BrightnessMappingStrategy { config = mDefaultConfig; } if (config.equals(mConfig)) { - if (DEBUG) { - Slog.d(TAG, "Tried to set an identical brightness config, ignoring"); - } return false; } Pair curve = config.getCurve(); - mBrightnessSpline = Spline.createSpline(curve.first /*lux*/, curve.second /*nits*/); - if (DEBUG) { - Slog.d(TAG, "Brightness spline: " + mBrightnessSpline); - final float[] lux = curve.first; - for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) { - Slog.d(TAG, String.format( - " %7.1f: %7.1f", v, mBrightnessSpline.interpolate(v))); - } - } + mBrightnessSpline = createSpline(curve.first /*lux*/, curve.second /*nits*/); mConfig = config; return true; } @Override public float getBrightness(float lux) { - return mNitsToBacklightSpline.interpolate(mBrightnessSpline.interpolate(lux)); + float nits = mBrightnessSpline.interpolate(lux); + float backlight = mNitsToBacklightSpline.interpolate(nits); + return backlight; } @Override - public float getNits(int backlight) { + public float convertToNits(int backlight) { return mBacklightToNitsSpline.interpolate(normalizeAbsoluteBrightness(backlight)); } + @Override + public void addUserDataPoint(float lux, float backlight) { + if (DEBUG){ + Slog.d(TAG, "addUserDataPoint(lux=" + lux + ", backlight=" + backlight + ")"); + } + float brightness = mBacklightToNitsSpline.interpolate(backlight); + Pair defaultCurve = mConfig.getCurve(); + Pair newCurve = + insertControlPoint(defaultCurve.first, defaultCurve.second, lux, brightness); + mBrightnessSpline = createSpline(newCurve.first, newCurve.second); + mUserLux = lux; + mUserBrightness = brightness; + } + + @Override + public void clearUserDataPoints() { + if (mUserLux != -1) { + Pair defaultCurve = mConfig.getCurve(); + mBrightnessSpline = createSpline(defaultCurve.first, defaultCurve.second); + mUserLux = -1; + mUserBrightness = -1; + } + } + @Override public void dump(PrintWriter pw) { pw.println("PhysicalMappingStrategy"); pw.println(" mConfig=" + mConfig); pw.println(" mBrightnessSpline=" + mBrightnessSpline); pw.println(" mNitsToBacklightSpline=" + mNitsToBacklightSpline); + pw.println(" mUserLux=" + mUserLux); + pw.println(" mUserBrightness=" + mUserBrightness); } } } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index c77ec20afa3b9..0c2ff05196150 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -1857,6 +1857,36 @@ public final class DisplayManagerService extends SystemService { } } + @Override // Binder call + public void setTemporaryBrightness(int brightness) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS, + "Permission required to set the display's brightness"); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mSyncRoot) { + mDisplayPowerController.setTemporaryBrightness(brightness); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public void setTemporaryAutoBrightnessAdjustment(float adjustment) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS, + "Permission required to set the display's auto brightness adjustment"); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mSyncRoot) { + mDisplayPowerController.setTemporaryAutoBrightnessAdjustment(adjustment); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + private boolean validatePackageName(int uid, String packageName) { if (packageName != null) { String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index d2b8e5c677b46..056c3e641c4a8 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -29,6 +29,7 @@ import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.ParceledListSlice; import android.content.res.Resources; +import android.database.ContentObserver; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; @@ -37,6 +38,7 @@ import android.hardware.display.BrightnessChangeEvent; import android.hardware.display.BrightnessConfiguration; import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks; import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; +import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -44,6 +46,8 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; +import android.os.UserHandle; +import android.provider.Settings; import android.util.MathUtils; import android.util.Slog; import android.util.Spline; @@ -99,6 +103,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private static final int MSG_SCREEN_ON_UNBLOCKED = 3; private static final int MSG_SCREEN_OFF_UNBLOCKED = 4; private static final int MSG_CONFIGURE_BRIGHTNESS = 5; + private static final int MSG_SET_TEMPORARY_BRIGHTNESS = 6; + private static final int MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT = 7; private static final int PROXIMITY_UNKNOWN = -1; private static final int PROXIMITY_NEGATIVE = 0; @@ -144,6 +150,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // The display blanker. private final DisplayBlanker mBlanker; + // Tracker for brightness changes. + private final BrightnessTracker mBrightnessTracker; + + // Tracker for brightness settings changes. + private final SettingsObserver mSettingsObserver; + // The proximity sensor, or null if not available or needed. private Sensor mProximitySensor; @@ -159,6 +171,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // The maximum allowed brightness. private final int mScreenBrightnessRangeMaximum; + // The default screen brightness. + private final int mScreenBrightnessDefault; + + // The default screen brightness for VR. + private final int mScreenBrightnessForVrDefault; + // True if auto-brightness should be used. private boolean mUseSoftwareAutoBrightnessConfig; @@ -298,20 +316,42 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // The last brightness that was set by the user and not temporary. Set to -1 when a brightness // has yet to be recorded. - private int mLastBrightness; + private int mLastUserSetScreenBrightness; + + // The screen brightenss setting has changed but not taken effect yet. If this is different + // from the current screen brightness setting then this is coming from something other than us + // and should be considered a user interaction. + private int mPendingScreenBrightnessSetting; + + // The last observed screen brightness setting, either set by us or by the settings app on + // behalf of the user. + private int mCurrentScreenBrightnessSetting; + + // The temporary screen brightness. Typically set when a user is interacting with the + // brightness slider but hasn't settled on a choice yet. Set to -1 when there's no temporary + // brightness set. + private int mTemporaryScreenBrightness; + + // The current screen brightness while in VR mode. + private int mScreenBrightnessForVr; // The last auto brightness adjustment that was set by the user and not temporary. Set to // Float.NaN when an auto-brightness adjustment hasn't been recorded yet. - private float mLastAutoBrightnessAdjustment; + private float mAutoBrightnessAdjustment; + + // The pending auto brightness adjustment that will take effect on the next power state update. + private float mPendingAutoBrightnessAdjustment; + + // The temporary auto brightness adjustment. Typically set when a user is interacting with the + // adjustment slider but hasn't settled on a choice yet. Set to Float.NaN when there's no + // temporary adjustment set. + private float mTemporaryAutoBrightnessAdjustment; // Animators. private ObjectAnimator mColorFadeOnAnimator; private ObjectAnimator mColorFadeOffAnimator; private RampAnimator mScreenBrightnessRampAnimator; - // Tracker for brightness changes - private final BrightnessTracker mBrightnessTracker; - /** * Creates the display power controller. */ @@ -320,6 +360,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call SensorManager sensorManager, DisplayBlanker blanker) { mHandler = new DisplayControllerHandler(handler.getLooper()); mBrightnessTracker = new BrightnessTracker(context, null); + mSettingsObserver = new SettingsObserver(mHandler); mCallbacks = callbacks; mBatteryStats = BatteryStatsService.getService(); @@ -343,6 +384,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mScreenBrightnessRangeMaximum = clampAbsoluteBrightness(resources.getInteger( com.android.internal.R.integer.config_screenBrightnessSettingMaximum)); + mScreenBrightnessDefault = clampAbsoluteBrightness(resources.getInteger( + com.android.internal.R.integer.config_screenBrightnessSettingDefault)); + mScreenBrightnessForVrDefault = clampAbsoluteBrightness(resources.getInteger( + com.android.internal.R.integer.config_screenBrightnessForVrSettingDefault)); mUseSoftwareAutoBrightnessConfig = resources.getBoolean( com.android.internal.R.bool.config_automatic_brightness_available); @@ -429,8 +474,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } - mLastBrightness = -1; - mLastAutoBrightnessAdjustment = Float.NaN; + mCurrentScreenBrightnessSetting = getScreenBrightnessSetting(); + mScreenBrightnessForVr = getScreenBrightnessForVrSetting(); + mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting(); + mTemporaryScreenBrightness = -1; + mTemporaryAutoBrightnessAdjustment = Float.NaN; } /** @@ -553,10 +601,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } // Initialize all of the brightness tracking state - final float brightness = getNits(mPowerState.getScreenBrightness()); + final float brightness = convertToNits(mPowerState.getScreenBrightness()); if (brightness >= 0.0f) { mBrightnessTracker.start(brightness); } + + mContext.getContentResolver().registerContentObserver( + Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS), + false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL); + mContext.getContentResolver().registerContentObserver( + Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ), + false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL); } private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() { @@ -586,7 +641,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Update the power state request. final boolean mustNotify; boolean mustInitialize = false; - boolean autoBrightnessAdjustmentChanged = false; synchronized (mLock) { mPendingUpdatePowerStateLocked = false; @@ -601,8 +655,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mPendingRequestChangedLocked = false; mustInitialize = true; } else if (mPendingRequestChangedLocked) { - autoBrightnessAdjustmentChanged = (mPowerRequest.screenAutoBrightnessAdjustment - != mPendingRequestLocked.screenAutoBrightnessAdjustment); mPowerRequest.copyFrom(mPendingRequestLocked); mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked; mPendingWaitForNegativeProximityLocked = false; @@ -691,6 +743,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call brightness = PowerManager.BRIGHTNESS_OFF; } + // Always use the VR brightness when in the VR state. + if (state == Display.STATE_VR) { + brightness = mScreenBrightnessForVr; + } + + if (brightness < 0 && mPowerRequest.screenBrightnessOverride > 0) { + brightness = mPowerRequest.screenBrightnessOverride; + } final boolean autoBrightnessEnabledInDoze = mAllowAutoBrightnessWhileDozingConfig && Display.isDozeState(state); @@ -698,38 +758,54 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call && (state == Display.STATE_ON || autoBrightnessEnabledInDoze) && brightness < 0 && mAutomaticBrightnessController != null; - final boolean brightnessAdjustmentChanged = - !Float.isNaN(mLastAutoBrightnessAdjustment) - && mPowerRequest.screenAutoBrightnessAdjustment != mLastAutoBrightnessAdjustment; - final boolean brightnessChanged = mLastBrightness >= 0 - && mPowerRequest.screenBrightness != mLastBrightness; + boolean brightnessIsTemporary = false; - // Update the last set brightness values. - final boolean userInitiatedChange; - if (mPowerRequest.brightnessSetByUser && !mPowerRequest.brightnessIsTemporary) { - userInitiatedChange = autoBrightnessEnabled && brightnessAdjustmentChanged - || !autoBrightnessEnabled && brightnessChanged; - mLastBrightness = mPowerRequest.screenBrightness; - mLastAutoBrightnessAdjustment = mPowerRequest.screenAutoBrightnessAdjustment; - } else { - userInitiatedChange = false; + final boolean userSetBrightnessChanged = updateUserSetScreenBrightness(); + if (userSetBrightnessChanged) { + mTemporaryScreenBrightness = -1; } + // Use the temporary screen brightness if there isn't an override, either from + // WindowManager or based on the display state. + if (mTemporaryScreenBrightness > 0) { + brightness = mTemporaryScreenBrightness; + brightnessIsTemporary = true; + } + + final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment(); + if (autoBrightnessAdjustmentChanged) { + mTemporaryAutoBrightnessAdjustment = Float.NaN; + } + + // Use the autobrightness adjustment override if set. + final float autoBrightnessAdjustment; + if (!Float.isNaN(mTemporaryAutoBrightnessAdjustment)) { + autoBrightnessAdjustment = mTemporaryAutoBrightnessAdjustment; + brightnessIsTemporary = true; + } else { + autoBrightnessAdjustment = mAutoBrightnessAdjustment; + } + + // Apply brightness boost. + // We do this here after deciding whether auto-brightness is enabled so that we don't + // disable the light sensor during this temporary state. That way when boost ends we will + // be able to resume normal auto-brightness behavior without any delay. + if (mPowerRequest.boostScreenBrightness + && brightness != PowerManager.BRIGHTNESS_OFF) { + brightness = PowerManager.BRIGHTNESS_ON; + } + + // If the brightness is already set then it's been overriden by something other than the + // user, or is a temporary adjustment. + final boolean userInitiatedChange = brightness < 0 + && (autoBrightnessAdjustmentChanged || userSetBrightnessChanged); + // Configure auto-brightness. if (mAutomaticBrightnessController != null) { mAutomaticBrightnessController.configure(autoBrightnessEnabled, - mBrightnessConfiguration, mPowerRequest.screenAutoBrightnessAdjustment, - state != Display.STATE_ON, userInitiatedChange); - } - - // Apply brightness boost. - // We do this here after configuring auto-brightness so that we don't - // disable the light sensor during this temporary state. That way when - // boost ends we will be able to resume normal auto-brightness behavior - // without any delay. - if (mPowerRequest.boostScreenBrightness - && brightness != PowerManager.BRIGHTNESS_OFF) { - brightness = PowerManager.BRIGHTNESS_ON; + mBrightnessConfiguration, + mLastUserSetScreenBrightness / (float) PowerManager.BRIGHTNESS_ON, + autoBrightnessAdjustment, mPowerRequest.policy, userInitiatedChange); } // Apply auto-brightness. @@ -744,6 +820,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) { slowChange = true; // slowly adapt to auto-brightness } + // Tell the rest of the system about the new brightness. Note that we do this + // before applying the low power or dim transformations so that the slider + // accurately represents the full possible range, even if they range changes what + // it means in absolute terms. + putScreenBrightnessSetting(brightness); mAppliedAutoBrightness = true; } else { mAppliedAutoBrightness = false; @@ -762,9 +843,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // provide a nominal default value for the case where auto-brightness // is not ready yet. if (brightness < 0) { - brightness = clampScreenBrightness(mPowerRequest.screenBrightness); + brightness = clampScreenBrightness(mLastUserSetScreenBrightness); } + // Apply dimming by at least some minimum amount when user activity // timeout is about to expire. if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) { @@ -833,19 +915,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call final boolean isDisplayContentVisible = mColorFadeEnabled && mPowerState.getColorFadeLevel() == 1.0f; if (initialRampSkip || hasBrightnessBuckets - || wasOrWillBeInVr || !isDisplayContentVisible) { + || wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) { animateScreenBrightness(brightness, 0); } else { animateScreenBrightness(brightness, slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast); } - final float brightnessInNits = getNits(brightness); - if (!mPowerRequest.brightnessIsTemporary && brightnessInNits >= 0.0f) { - // We only want to track changes made by the user and on devices that can actually - // map the display backlight values into a physical brightness unit. - mBrightnessTracker.notifyBrightnessChanged(brightnessInNits, userInitiatedChange); + if (!brightnessIsTemporary) { + notifyBrightnessChanged(brightness, userInitiatedChange); } + } // Determine whether the display is ready for use in the newly requested state. @@ -913,6 +993,18 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call msg.sendToTarget(); } + public void setTemporaryBrightness(int brightness) { + Message msg = mHandler.obtainMessage(MSG_SET_TEMPORARY_BRIGHTNESS, + brightness, 0 /*unused*/); + msg.sendToTarget(); + } + + public void setTemporaryAutoBrightnessAdjustment(float adjustment) { + Message msg = mHandler.obtainMessage(MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT, + Float.floatToIntBits(adjustment), 0 /*unused*/); + msg.sendToTarget(); + } + private void blockScreenOn() { if (mPendingScreenOnUnblocker == null) { Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0); @@ -1304,9 +1396,79 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mHandler.post(mOnStateChangedRunnable); } - private float getNits(int backlight) { + private void handleSettingsChange() { + mPendingScreenBrightnessSetting = getScreenBrightnessSetting(); + mPendingAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting(); + // We don't bother with a pending variable for VR screen brightness since we just + // immediately adapt to it. + mScreenBrightnessForVr = getScreenBrightnessForVrSetting(); + sendUpdatePowerState(); + } + + private float getAutoBrightnessAdjustmentSetting() { + final float adj = Settings.System.getFloatForUser(mContext.getContentResolver(), + Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, UserHandle.USER_CURRENT); + return Float.isNaN(adj) ? 0.0f : clampAutoBrightnessAdjustment(adj); + } + + private int getScreenBrightnessSetting() { + final int brightness = Settings.System.getIntForUser(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS, mScreenBrightnessDefault, + UserHandle.USER_CURRENT); + return clampAbsoluteBrightness(brightness); + } + + private int getScreenBrightnessForVrSetting() { + final int brightness = Settings.System.getIntForUser(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_FOR_VR, mScreenBrightnessForVrDefault, + UserHandle.USER_CURRENT); + return clampAbsoluteBrightness(brightness); + } + + private void putScreenBrightnessSetting(int brightness) { + mCurrentScreenBrightnessSetting = brightness; + Settings.System.putIntForUser(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS, brightness, + UserHandle.USER_CURRENT); + } + + private boolean updateAutoBrightnessAdjustment() { + if (Float.isNaN(mPendingAutoBrightnessAdjustment)) { + return false; + } + if (mAutoBrightnessAdjustment == mPendingAutoBrightnessAdjustment) { + return false; + } + mAutoBrightnessAdjustment = mPendingAutoBrightnessAdjustment; + mPendingAutoBrightnessAdjustment = Float.NaN; + return true; + } + + private boolean updateUserSetScreenBrightness() { + if (mPendingScreenBrightnessSetting < 0) { + return false; + } + if (mCurrentScreenBrightnessSetting == mPendingScreenBrightnessSetting) { + return false; + } + mLastUserSetScreenBrightness = mPendingScreenBrightnessSetting; + mPendingScreenBrightnessSetting = -1; + return true; + } + + private void notifyBrightnessChanged(int brightness, boolean userInitiated) { + final float brightnessInNits = convertToNits(brightness); + if (brightnessInNits >= 0.0f) { + // We only want to track changes on devices that can actually map the display backlight + // values into a physical brightness unit since the value provided by the API is in + // nits and not using the arbitrary backlight units. + mBrightnessTracker.notifyBrightnessChanged(brightnessInNits, userInitiated); + } + } + + private float convertToNits(int backlight) { if (mBrightnessMapper != null) { - return mBrightnessMapper.getNits(backlight); + return mBrightnessMapper.convertToNits(backlight); } else { return -1.0f; } @@ -1390,8 +1552,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call pw.println(" mPendingProximityDebounceTime=" + TimeUtils.formatUptime(mPendingProximityDebounceTime)); pw.println(" mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity); - pw.println(" mLastBrightness=" + mLastBrightness); - pw.println(" mLastAutoBrightnessAdjustment=" + mLastAutoBrightnessAdjustment); + pw.println(" mLastUserSetScreenBrightness=" + mLastUserSetScreenBrightness); + pw.println(" mCurrentScreenBrightnessSetting=" + mCurrentScreenBrightnessSetting); + pw.println(" mPendingScreenBrightnessSetting=" + mPendingScreenBrightnessSetting); + pw.println(" mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment); + pw.println(" mPendingAutoBrightnessAdjustment=" + mPendingAutoBrightnessAdjustment); pw.println(" mAppliedAutoBrightness=" + mAppliedAutoBrightness); pw.println(" mAppliedDimming=" + mAppliedDimming); pw.println(" mAppliedLowPower=" + mAppliedLowPower); @@ -1456,6 +1621,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON); } + private static float clampAutoBrightnessAdjustment(float value) { + return MathUtils.constrain(value, -1.0f, 1.0f); + } + private final class DisplayControllerHandler extends Handler { public DisplayControllerHandler(Looper looper) { super(looper, null, true /*async*/); @@ -1488,6 +1657,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mBrightnessConfiguration = (BrightnessConfiguration)msg.obj; updatePowerState(); break; + + case MSG_SET_TEMPORARY_BRIGHTNESS: + // TODO: Should we have a a timeout for the temporary brightness? + mTemporaryScreenBrightness = msg.arg1; + updatePowerState(); + break; + + case MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT: + mTemporaryAutoBrightnessAdjustment = Float.intBitsToFloat(msg.arg1); + updatePowerState(); + break; } } } @@ -1509,6 +1689,18 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } }; + + private final class SettingsObserver extends ContentObserver { + public SettingsObserver(Handler handler) { + super(handler); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + handleSettingsChange(); + } + } + private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener { @Override public void onScreenOn() { diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index fbdedceabb3b3..cf36166757e23 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -70,6 +70,7 @@ import android.service.vr.IVrManager; import android.service.vr.IVrStateCallbacks; import android.util.EventLog; import android.util.KeyValueListParser; +import android.util.MathUtils; import android.util.PrintWriterPrinter; import android.util.Slog; import android.util.SparseArray; @@ -458,19 +459,11 @@ public final class PowerManagerService extends SystemService private int mScreenBrightnessSettingMinimum; private int mScreenBrightnessSettingMaximum; private int mScreenBrightnessSettingDefault; - private int mScreenBrightnessForVrSettingDefault; // The screen brightness setting, from 0 to 255. // Use -1 if no value has been set. private int mScreenBrightnessSetting; - // The screen brightness setting, from 0 to 255, to be used while in VR Mode. - private int mScreenBrightnessForVrSetting; - - // The screen auto-brightness adjustment setting, from -1 to 1. - // Use 0 if there is no adjustment. - private float mScreenAutoBrightnessAdjustmentSetting; - // The screen brightness mode. // One of the Settings.System.SCREEN_BRIGHTNESS_MODE_* constants. private int mScreenBrightnessModeSetting; @@ -493,17 +486,6 @@ public final class PowerManagerService extends SystemService // Use -1 to disable. private long mUserActivityTimeoutOverrideFromWindowManager = -1; - // The screen brightness setting override from the settings application - // to temporarily adjust the brightness until next updated, - // Use -1 to disable. - private int mTemporaryScreenBrightnessSettingOverride = -1; - - // The screen brightness adjustment setting override from the settings - // application to temporarily adjust the auto-brightness adjustment factor - // until next updated, in the range -1..1. - // Use NaN to disable. - private float mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = Float.NaN; - // The screen state to use while dozing. private int mDozeScreenStateOverrideFromDreamManager = Display.STATE_UNKNOWN; @@ -774,7 +756,6 @@ public final class PowerManagerService extends SystemService mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting(); mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting(); mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting(); - mScreenBrightnessForVrSettingDefault = pm.getDefaultScreenBrightnessForVrSetting(); SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper()); @@ -836,12 +817,6 @@ public final class PowerManagerService extends SystemService resolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.STAY_ON_WHILE_PLUGGED_IN), false, mSettingsObserver, UserHandle.USER_ALL); - resolver.registerContentObserver(Settings.System.getUriFor( - Settings.System.SCREEN_BRIGHTNESS), - false, mSettingsObserver, UserHandle.USER_ALL); - resolver.registerContentObserver(Settings.System.getUriFor( - Settings.System.SCREEN_BRIGHTNESS_FOR_VR), - false, mSettingsObserver, UserHandle.USER_ALL); resolver.registerContentObserver(Settings.System.getUriFor( Settings.System.SCREEN_BRIGHTNESS_MODE), false, mSettingsObserver, UserHandle.USER_ALL); @@ -978,29 +953,6 @@ public final class PowerManagerService extends SystemService SystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, retailDemoValue); } - final int oldScreenBrightnessSetting = getCurrentBrightnessSettingLocked(); - - mScreenBrightnessForVrSetting = Settings.System.getIntForUser(resolver, - Settings.System.SCREEN_BRIGHTNESS_FOR_VR, mScreenBrightnessForVrSettingDefault, - UserHandle.USER_CURRENT); - - mScreenBrightnessSetting = Settings.System.getIntForUser(resolver, - Settings.System.SCREEN_BRIGHTNESS, mScreenBrightnessSettingDefault, - UserHandle.USER_CURRENT); - - if (oldScreenBrightnessSetting != getCurrentBrightnessSettingLocked()) { - mTemporaryScreenBrightnessSettingOverride = -1; - } - - final float oldScreenAutoBrightnessAdjustmentSetting = - mScreenAutoBrightnessAdjustmentSetting; - mScreenAutoBrightnessAdjustmentSetting = Settings.System.getFloatForUser(resolver, - Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, - UserHandle.USER_CURRENT); - if (oldScreenAutoBrightnessAdjustmentSetting != mScreenAutoBrightnessAdjustmentSetting) { - mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = Float.NaN; - } - mScreenBrightnessModeSetting = Settings.System.getIntForUser(resolver, Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT); @@ -1019,10 +971,6 @@ public final class PowerManagerService extends SystemService mDirty |= DIRTY_SETTINGS; } - private int getCurrentBrightnessSettingLocked() { - return mIsVrModeEnabled ? mScreenBrightnessForVrSetting : mScreenBrightnessSetting; - } - private void postAfterBootCompleted(Runnable r) { if (mBootCompleted) { BackgroundThread.getHandler().post(r); @@ -2450,53 +2398,24 @@ public final class PowerManagerService extends SystemService mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked(); // Determine appropriate screen brightness and auto-brightness adjustments. - boolean brightnessSetByUser = true; - int screenBrightness = mScreenBrightnessSettingDefault; - float screenAutoBrightnessAdjustment = 0.0f; - boolean autoBrightness = (mScreenBrightnessModeSetting == - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - boolean brightnessIsTemporary = false; + final boolean autoBrightness; + final int screenBrightnessOverride; if (!mBootCompleted) { // Keep the brightness steady during boot. This requires the // bootloader brightness and the default brightness to be identical. autoBrightness = false; - brightnessSetByUser = false; - } else if (mIsVrModeEnabled) { - screenBrightness = mScreenBrightnessForVrSetting; - autoBrightness = false; + screenBrightnessOverride = mScreenBrightnessSettingDefault; } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) { - screenBrightness = mScreenBrightnessOverrideFromWindowManager; autoBrightness = false; - brightnessSetByUser = false; - } else if (isValidBrightness(mTemporaryScreenBrightnessSettingOverride)) { - screenBrightness = mTemporaryScreenBrightnessSettingOverride; - brightnessIsTemporary = true; - } else if (isValidBrightness(mScreenBrightnessSetting)) { - screenBrightness = mScreenBrightnessSetting; + screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager; + } else { + autoBrightness = (mScreenBrightnessModeSetting == + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); + screenBrightnessOverride = -1; } - if (autoBrightness) { - screenBrightness = mScreenBrightnessSettingDefault; - if (isValidAutoBrightnessAdjustment( - mTemporaryScreenAutoBrightnessAdjustmentSettingOverride)) { - screenAutoBrightnessAdjustment = - mTemporaryScreenAutoBrightnessAdjustmentSettingOverride; - brightnessIsTemporary = true; - } else if (isValidAutoBrightnessAdjustment( - mScreenAutoBrightnessAdjustmentSetting)) { - screenAutoBrightnessAdjustment = mScreenAutoBrightnessAdjustmentSetting; - } - } - screenBrightness = Math.max(Math.min(screenBrightness, - mScreenBrightnessSettingMaximum), mScreenBrightnessSettingMinimum); - screenAutoBrightnessAdjustment = Math.max(Math.min( - screenAutoBrightnessAdjustment, 1.0f), -1.0f); // Update display power request. - mDisplayPowerRequest.screenBrightness = screenBrightness; - mDisplayPowerRequest.screenAutoBrightnessAdjustment = - screenAutoBrightnessAdjustment; - mDisplayPowerRequest.brightnessSetByUser = brightnessSetByUser; - mDisplayPowerRequest.brightnessIsTemporary = brightnessIsTemporary; + mDisplayPowerRequest.screenBrightnessOverride = screenBrightnessOverride; mDisplayPowerRequest.useAutoBrightness = autoBrightness; mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked(); mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness(); @@ -2534,6 +2453,8 @@ public final class PowerManagerService extends SystemService + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary) + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary) + ", mBootCompleted=" + mBootCompleted + + ", screenBrightnessOverride=" + screenBrightnessOverride + + ", useAutoBrightness=" + autoBrightness + ", mScreenBrightnessBoostInProgress=" + mScreenBrightnessBoostInProgress + ", mIsVrModeEnabled= " + mIsVrModeEnabled + ", sQuiescent=" + sQuiescent); @@ -2573,11 +2494,6 @@ public final class PowerManagerService extends SystemService return value >= 0 && value <= 255; } - private static boolean isValidAutoBrightnessAdjustment(float value) { - // Handles NaN by always returning false. - return value >= -1.0f && value <= 1.0f; - } - @VisibleForTesting int getDesiredScreenPolicyLocked() { if (mWakefulness == WAKEFULNESS_ASLEEP || sQuiescent) { @@ -3247,28 +3163,6 @@ public final class PowerManagerService extends SystemService } } - private void setTemporaryScreenBrightnessSettingOverrideInternal(int brightness) { - synchronized (mLock) { - if (mTemporaryScreenBrightnessSettingOverride != brightness) { - mTemporaryScreenBrightnessSettingOverride = brightness; - mDirty |= DIRTY_SETTINGS; - updatePowerStateLocked(); - } - } - } - - private void setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(float adj) { - synchronized (mLock) { - // Note: This condition handles NaN because NaN is not equal to any other - // value, including itself. - if (mTemporaryScreenAutoBrightnessAdjustmentSettingOverride != adj) { - mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = adj; - mDirty |= DIRTY_SETTINGS; - updatePowerStateLocked(); - } - } - } - private void setDozeOverrideFromDreamManagerInternal( int screenState, int screenBrightness) { synchronized (mLock) { @@ -3478,8 +3372,6 @@ public final class PowerManagerService extends SystemService + isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked() + ")"); pw.println(" mStayOnWhilePluggedInSetting=" + mStayOnWhilePluggedInSetting); pw.println(" mScreenBrightnessSetting=" + mScreenBrightnessSetting); - pw.println(" mScreenAutoBrightnessAdjustmentSetting=" - + mScreenAutoBrightnessAdjustmentSetting); pw.println(" mScreenBrightnessModeSetting=" + mScreenBrightnessModeSetting); pw.println(" mScreenBrightnessOverrideFromWindowManager=" + mScreenBrightnessOverrideFromWindowManager); @@ -3487,10 +3379,6 @@ public final class PowerManagerService extends SystemService + mUserActivityTimeoutOverrideFromWindowManager); pw.println(" mUserInactiveOverrideFromWindowManager=" + mUserInactiveOverrideFromWindowManager); - pw.println(" mTemporaryScreenBrightnessSettingOverride=" - + mTemporaryScreenBrightnessSettingOverride); - pw.println(" mTemporaryScreenAutoBrightnessAdjustmentSettingOverride=" - + mTemporaryScreenAutoBrightnessAdjustmentSettingOverride); pw.println(" mDozeScreenStateOverrideFromDreamManager=" + mDozeScreenStateOverrideFromDreamManager); pw.println(" mDozeScreenBrightnessOverrideFromDreamManager=" @@ -3498,9 +3386,6 @@ public final class PowerManagerService extends SystemService pw.println(" mScreenBrightnessSettingMinimum=" + mScreenBrightnessSettingMinimum); pw.println(" mScreenBrightnessSettingMaximum=" + mScreenBrightnessSettingMaximum); pw.println(" mScreenBrightnessSettingDefault=" + mScreenBrightnessSettingDefault); - pw.println(" mScreenBrightnessForVrSettingDefault=" - + mScreenBrightnessForVrSettingDefault); - pw.println(" mScreenBrightnessForVrSetting=" + mScreenBrightnessForVrSetting); pw.println(" mDoubleTapWakeEnabled=" + mDoubleTapWakeEnabled); pw.println(" mIsVrModeEnabled=" + mIsVrModeEnabled); pw.println(" mForegroundProfile=" + mForegroundProfile); @@ -3811,13 +3696,6 @@ public final class PowerManagerService extends SystemService != 0)); proto.end(stayOnWhilePluggedInToken); - proto.write( - PowerServiceSettingsAndConfigurationDumpProto.SCREEN_BRIGHTNESS_SETTING, - mScreenBrightnessSetting); - proto.write( - PowerServiceSettingsAndConfigurationDumpProto - .SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_SETTING, - mScreenAutoBrightnessAdjustmentSetting); proto.write( PowerServiceSettingsAndConfigurationDumpProto.SCREEN_BRIGHTNESS_MODE_SETTING, mScreenBrightnessModeSetting); @@ -3833,14 +3711,6 @@ public final class PowerManagerService extends SystemService PowerServiceSettingsAndConfigurationDumpProto .IS_USER_INACTIVE_OVERRIDE_FROM_WINDOW_MANAGER, mUserInactiveOverrideFromWindowManager); - proto.write( - PowerServiceSettingsAndConfigurationDumpProto - .TEMPORARY_SCREEN_BRIGHTNESS_SETTING_OVERRIDE, - mTemporaryScreenBrightnessSettingOverride); - proto.write( - PowerServiceSettingsAndConfigurationDumpProto - .TEMPORARY_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_SETTING_OVERRIDE, - mTemporaryScreenAutoBrightnessAdjustmentSettingOverride); proto.write( PowerServiceSettingsAndConfigurationDumpProto .DOZE_SCREEN_STATE_OVERRIDE_FROM_DREAM_MANAGER, @@ -3866,15 +3736,8 @@ public final class PowerManagerService extends SystemService PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto .SETTING_DEFAULT, mScreenBrightnessSettingDefault); - proto.write( - PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto - .SETTING_FOR_VR_DEFAULT, - mScreenBrightnessForVrSettingDefault); proto.end(screenBrightnessSettingLimitsToken); - proto.write( - PowerServiceSettingsAndConfigurationDumpProto.SCREEN_BRIGHTNESS_FOR_VR_SETTING, - mScreenBrightnessForVrSetting); proto.write( PowerServiceSettingsAndConfigurationDumpProto.IS_DOUBLE_TAP_WAKE_ENABLED, mDoubleTapWakeEnabled); @@ -4708,56 +4571,6 @@ public final class PowerManagerService extends SystemService } } - /** - * Used by the settings application and brightness control widgets to - * temporarily override the current screen brightness setting so that the - * user can observe the effect of an intended settings change without applying - * it immediately. - * - * The override will be canceled when the setting value is next updated. - * - * @param brightness The overridden brightness. - * - * @see android.provider.Settings.System#SCREEN_BRIGHTNESS - */ - @Override // Binder call - public void setTemporaryScreenBrightnessSettingOverride(int brightness) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.DEVICE_POWER, null); - - final long ident = Binder.clearCallingIdentity(); - try { - setTemporaryScreenBrightnessSettingOverrideInternal(brightness); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - /** - * Used by the settings application and brightness control widgets to - * temporarily override the current screen auto-brightness adjustment setting so that the - * user can observe the effect of an intended settings change without applying - * it immediately. - * - * The override will be canceled when the setting value is next updated. - * - * @param adj The overridden brightness, or Float.NaN to disable the override. - * - * @see android.provider.Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ - */ - @Override // Binder call - public void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float adj) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.DEVICE_POWER, null); - - final long ident = Binder.clearCallingIdentity(); - try { - setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(adj); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - /** * Used by the phone application to make the attention LED flash when ringing. */ diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java index 9e7ef6539c2bb..fb25cf3f01e0b 100644 --- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java +++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java @@ -281,6 +281,68 @@ public class BrightnessMappingStrategyTest { assertNull(physical); } + @Test + public void testStrategiesAdaptToUserDataPoint() { + Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS, + DISPLAY_RANGE_NITS, BACKLIGHT_RANGE); + assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res)); + res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT); + assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res)); + } + + private static void assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy strategy) { + // Save out all of the initial brightness data for comparison after reset. + float[] initialBrightnessLevels = new float[LUX_LEVELS.length]; + for (int i = 0; i < LUX_LEVELS.length; i++) { + initialBrightnessLevels[i] = strategy.getBrightness(LUX_LEVELS[i]); + } + + // Add a data point in the middle of the curve where the user has set the brightness max + final int idx = LUX_LEVELS.length / 2; + strategy.addUserDataPoint(LUX_LEVELS[idx], 1.0f); + + // Then make sure that all control points after the middle lux level are also set to max... + for (int i = idx; i < LUX_LEVELS.length; i++) { + assertEquals(strategy.getBrightness(LUX_LEVELS[idx]), 1.0, 0.01 /*tolerance*/); + } + + // ...and that all control points before the middle lux level are strictly less than the + // previous one still. + float prevBrightness = strategy.getBrightness(LUX_LEVELS[idx]); + for (int i = idx - 1; i >= 0; i--) { + float brightness = strategy.getBrightness(LUX_LEVELS[i]); + assertTrue("Brightness levels must be monotonic after adapting to user data", + prevBrightness >= brightness); + prevBrightness = brightness; + } + + // Now reset the curve and make sure we go back to the initial brightness levels recorded + // before adding the user data point. + strategy.clearUserDataPoints(); + for (int i = 0; i < LUX_LEVELS.length; i++) { + assertEquals(initialBrightnessLevels[i], strategy.getBrightness(LUX_LEVELS[i]), + 0.01 /*tolerance*/); + } + + // Now set the middle of the lux range to something just above the minimum. + final float minBrightness = strategy.getBrightness(LUX_LEVELS[0]); + strategy.addUserDataPoint(LUX_LEVELS[idx], minBrightness + 0.01f); + + // Then make sure the curve is still monotonic. + prevBrightness = 0f; + for (float lux : LUX_LEVELS) { + float brightness = strategy.getBrightness(lux); + assertTrue("Brightness levels must be monotonic after adapting to user data", + prevBrightness <= brightness); + prevBrightness = brightness; + } + + // And that the lowest lux level still gives the absolute minimum brightness. This should + // be true assuming that there are more than two lux levels in the curve since we picked a + // brightness just barely above the minimum for the middle of the curve. + assertEquals(minBrightness, strategy.getBrightness(LUX_LEVELS[0]), 0.001 /*tolerance*/); + } + private static float[] toFloatArray(int[] vals) { float[] newVals = new float[vals.length]; for (int i = 0; i < vals.length; i++) {