Set initial screen brightness earlier in the boot process.

Previously we had to wait for systemReady before setting the brightness
due to the order in which the display power controller was initialized.
Unfortunately it could take us a rather long time to reach that stage,
particularly after an OTA where the screen would remain at maximum
brightness for minutes while "Optimizing Apps".

This change moves the brightness backlight setting code deeper
into the display manager which has a couple of nice side-benefits
in that it now becomes much easier to coordinate display power mode
changes with display backlight changes.  So this change also resolves
some issued with changing the backlight while in DOZE_SUSPEND and
ensuring that backlight changes generally end up being performed
before executing a power mode change except in the case where the
display needs to come out of suspend first.  (So now the backlight
will be set before entering DOZE from the ON state.)

Deleted some dead code in LightService which was in the way.

Bug: 19029490
Change-Id: I494b5223e676248daf2ff8be3ec338845977f73c
diff --git a/services/core/java/com/android/server/display/DisplayBlanker.java b/services/core/java/com/android/server/display/DisplayBlanker.java
index eb0ae6a..816dc13 100644
--- a/services/core/java/com/android/server/display/DisplayBlanker.java
+++ b/services/core/java/com/android/server/display/DisplayBlanker.java
@@ -20,5 +20,5 @@
  * Interface used to update the actual display state.
  */
 public interface DisplayBlanker {
-    void requestDisplayState(int state);
+    void requestDisplayState(int state, int brightness);
 }
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 61631d4..e16be71 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -118,10 +118,12 @@
     /**
      * Sets the display state, if supported.
      *
+     * @param state The new display state.
+     * @param brightness The new display brightness.
      * @return A runnable containing work to be deferred until after we have
      * exited the critical section, or null if none.
      */
-    public Runnable requestDisplayStateLocked(int state) {
+    public Runnable requestDisplayStateLocked(int state, int brightness) {
         return null;
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 5f0ad9f..9ea0444 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -40,11 +40,13 @@
 import android.os.IBinder.DeathRecipient;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -179,7 +181,11 @@
 
     // The overall display state, independent of changes that might influence one
     // display or another in particular.
-    private int mGlobalDisplayState = Display.STATE_UNKNOWN;
+    private int mGlobalDisplayState = Display.STATE_ON;
+
+    // The overall display brightness.
+    // For now, this only applies to the built-in display but we may split it up eventually.
+    private int mGlobalDisplayBrightness = PowerManager.BRIGHTNESS_DEFAULT;
 
     // Set to true when there are pending display changes that have yet to be applied
     // to the surface flinger state.
@@ -226,6 +232,9 @@
         mUiHandler = UiThread.getHandler();
         mDisplayAdapterListener = new DisplayAdapterListener();
         mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
+
+        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
     }
 
     @Override
@@ -322,16 +331,34 @@
         }
     }
 
-    private void requestGlobalDisplayStateInternal(int state) {
+    private void requestGlobalDisplayStateInternal(int state, int brightness) {
+        if (state == Display.STATE_UNKNOWN) {
+            state = Display.STATE_ON;
+        }
+        if (state == Display.STATE_OFF) {
+            brightness = PowerManager.BRIGHTNESS_OFF;
+        } else if (brightness < 0) {
+            brightness = PowerManager.BRIGHTNESS_DEFAULT;
+        } else if (brightness > PowerManager.BRIGHTNESS_ON) {
+            brightness = PowerManager.BRIGHTNESS_ON;
+        }
+
         synchronized (mTempDisplayStateWorkQueue) {
             try {
                 // Update the display state within the lock.
                 synchronized (mSyncRoot) {
-                    if (mGlobalDisplayState != state) {
-                        mGlobalDisplayState = state;
-                        updateGlobalDisplayStateLocked(mTempDisplayStateWorkQueue);
-                        scheduleTraversalLocked(false);
+                    if (mGlobalDisplayState == state
+                            && mGlobalDisplayBrightness == brightness) {
+                        return; // no change
                     }
+
+                    Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestGlobalDisplayState("
+                            + Display.stateToString(state)
+                            + ", brightness=" + brightness + ")");
+                    mGlobalDisplayState = state;
+                    mGlobalDisplayBrightness = brightness;
+                    updateGlobalDisplayStateLocked(mTempDisplayStateWorkQueue);
+                    scheduleTraversalLocked(false);
                 }
 
                 // Setting the display power state can take hundreds of milliseconds
@@ -341,6 +368,7 @@
                 for (int i = 0; i < mTempDisplayStateWorkQueue.size(); i++) {
                     mTempDisplayStateWorkQueue.get(i).run();
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_POWER);
             } finally {
                 mTempDisplayStateWorkQueue.clear();
             }
@@ -708,7 +736,7 @@
         // by the display power controller (if known).
         DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
-            return device.requestDisplayStateLocked(mGlobalDisplayState);
+            return device.requestDisplayStateLocked(mGlobalDisplayState, mGlobalDisplayBrightness);
         }
         return null;
     }
@@ -1462,16 +1490,16 @@
             synchronized (mSyncRoot) {
                 DisplayBlanker blanker = new DisplayBlanker() {
                     @Override
-                    public void requestDisplayState(int state) {
+                    public void requestDisplayState(int state, int brightness) {
                         // The order of operations is important for legacy reasons.
                         if (state == Display.STATE_OFF) {
-                            requestGlobalDisplayStateInternal(state);
+                            requestGlobalDisplayStateInternal(state, brightness);
                         }
 
                         callbacks.onDisplayStateChange(state);
 
                         if (state != Display.STATE_OFF) {
-                            requestGlobalDisplayStateInternal(state);
+                            requestGlobalDisplayStateInternal(state, brightness);
                         }
                     }
                 };
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index cf1f4b0..f74601e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -19,7 +19,6 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.server.LocalServices;
 import com.android.server.am.BatteryStatsService;
-import com.android.server.lights.LightsManager;
 
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
@@ -122,9 +121,6 @@
     // Battery stats.
     private final IBatteryStats mBatteryStats;
 
-    // The lights service.
-    private final LightsManager mLights;
-
     // The sensor manager.
     private final SensorManager mSensorManager;
 
@@ -260,7 +256,6 @@
         mCallbacks = callbacks;
 
         mBatteryStats = BatteryStatsService.getService();
-        mLights = LocalServices.getService(LightsManager.class);
         mSensorManager = sensorManager;
         mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class);
         mBlanker = blanker;
@@ -443,7 +438,6 @@
         // Initialize the power state object for the default display.
         // In the future, we might manage multiple displays independently.
         mPowerState = new DisplayPowerState(mBlanker,
-                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
                 new ColorFade(Display.DEFAULT_DISPLAY));
 
         mColorFadeOnAnimator = ObjectAnimator.ofFloat(
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index a3c9738..f53ccc9 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -16,13 +16,10 @@
 
 package com.android.server.display;
 
-import com.android.server.lights.Light;
-
 import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
-import android.os.Trace;
 import android.util.FloatProperty;
 import android.util.IntProperty;
 import android.util.Slog;
@@ -56,7 +53,6 @@
     private final Handler mHandler;
     private final Choreographer mChoreographer;
     private final DisplayBlanker mBlanker;
-    private final Light mBacklight;
     private final ColorFade mColorFade;
     private final PhotonicModulator mPhotonicModulator;
 
@@ -72,12 +68,11 @@
 
     private Runnable mCleanListener;
 
-    public DisplayPowerState(DisplayBlanker blanker, Light backlight, ColorFade electronBeam) {
+    public DisplayPowerState(DisplayBlanker blanker, ColorFade colorFade) {
         mHandler = new Handler(true /*async*/);
         mChoreographer = Choreographer.getInstance();
         mBlanker = blanker;
-        mBacklight = backlight;
-        mColorFade = electronBeam;
+        mColorFade = colorFade;
         mPhotonicModulator = new PhotonicModulator();
         mPhotonicModulator.start();
 
@@ -415,35 +410,7 @@
                     Slog.d(TAG, "Updating screen state: state="
                             + Display.stateToString(state) + ", backlight=" + backlight);
                 }
-                boolean suspending = Display.isSuspendedState(state);
-                if (stateChanged && !suspending) {
-                    requestDisplayState(state);
-                }
-                if (backlightChanged) {
-                    setBrightness(backlight);
-                }
-                if (stateChanged && suspending) {
-                    requestDisplayState(state);
-                }
-            }
-        }
-
-        private void requestDisplayState(int state) {
-            Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
-                    + Display.stateToString(state) + ")");
-            try {
-                mBlanker.requestDisplayState(state);
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_POWER);
-            }
-        }
-
-        private void setBrightness(int backlight) {
-            Trace.traceBegin(Trace.TRACE_TAG_POWER, "setBrightness(" + backlight + ")");
-            try {
-                mBacklight.setBrightness(backlight);
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_POWER);
+                mBlanker.requestDisplayState(state, backlight);
             }
         }
     }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 5ebe64d..e87f265 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -16,10 +16,15 @@
 
 package com.android.server.display;
 
+import com.android.server.LocalServices;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
+
 import android.content.Context;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.PowerManager;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.Slog;
@@ -40,6 +45,7 @@
  */
 final class LocalDisplayAdapter extends DisplayAdapter {
     private static final String TAG = "LocalDisplayAdapter";
+    private static final boolean DEBUG = false;
 
     private static final String UNIQUE_ID_PREFIX = "local:";
 
@@ -132,14 +138,17 @@
         private final int mBuiltInDisplayId;
         private final SurfaceControl.PhysicalDisplayInfo mPhys;
         private final int mDefaultPhysicalDisplayInfo;
+        private final Light mBacklight;
 
         private DisplayDeviceInfo mInfo;
         private boolean mHavePendingChanges;
         private int mState = Display.STATE_UNKNOWN;
+        private int mBrightness = PowerManager.BRIGHTNESS_DEFAULT;
         private float[] mSupportedRefreshRates;
         private int[] mRefreshRateConfigIndices;
         private float mLastRequestedRefreshRate;
 
+
         public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
                 SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo) {
             super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + builtInDisplayId);
@@ -148,6 +157,13 @@
                     physicalDisplayInfos[activeDisplayInfo]);
             mDefaultPhysicalDisplayInfo = activeDisplayInfo;
             updateSupportedRefreshRatesLocked(physicalDisplayInfos, mPhys);
+
+            if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
+                LightsManager lights = LocalServices.getService(LightsManager.class);
+                mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT);
+            } else {
+                mBacklight = null;
+            }
         }
 
         public boolean updatePhysicalDisplayInfoLocked(
@@ -225,28 +241,91 @@
         }
 
         @Override
-        public Runnable requestDisplayStateLocked(final int state) {
-            if (mState != state) {
+        public Runnable requestDisplayStateLocked(final int state, final int brightness) {
+            // Assume that the brightness is off if the display is being turned off.
+            assert state != Display.STATE_OFF || brightness == PowerManager.BRIGHTNESS_OFF;
+
+            final boolean stateChanged = (mState != state);
+            final boolean brightnessChanged = (mBrightness != brightness) && mBacklight != null;
+            if (stateChanged || brightnessChanged) {
                 final int displayId = mBuiltInDisplayId;
                 final IBinder token = getDisplayTokenLocked();
-                final int mode = getPowerModeForState(state);
-                mState = state;
-                updateDeviceInfoLocked();
+                final int oldState = mState;
 
-                // Defer actually setting the display power mode until we have exited
+                if (stateChanged) {
+                    mState = state;
+                    updateDeviceInfoLocked();
+                }
+
+                if (brightnessChanged) {
+                    mBrightness = brightness;
+                }
+
+                // Defer actually setting the display state until after we have exited
                 // the critical section since it can take hundreds of milliseconds
                 // to complete.
                 return new Runnable() {
                     @Override
                     public void run() {
-                        Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
-                                + Display.stateToString(state) + ", id=" + displayId + ")");
+                        // Exit a suspended state before making any changes.
+                        int currentState = oldState;
+                        if (Display.isSuspendedState(oldState)
+                                || oldState == Display.STATE_UNKNOWN) {
+                            if (!Display.isSuspendedState(state)) {
+                                setDisplayState(state);
+                                currentState = state;
+                            } else if (state == Display.STATE_DOZE_SUSPEND
+                                    || oldState == Display.STATE_DOZE_SUSPEND) {
+                                setDisplayState(Display.STATE_DOZE);
+                                currentState = Display.STATE_DOZE;
+                            } else {
+                                return; // old state and new state is off
+                            }
+                        }
+
+                        // Apply brightness changes given that we are in a non-suspended state.
+                        if (brightnessChanged) {
+                            setDisplayBrightness(brightness);
+                        }
+
+                        // Enter the final desired state, possibly suspended.
+                        if (state != currentState) {
+                            setDisplayState(state);
+                        }
+                    }
+
+                    private void setDisplayState(int state) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "setDisplayState("
+                                    + "id=" + displayId
+                                    + ", state=" + Display.stateToString(state) + ")");
+                        }
+
+                        Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayState("
+                                + "id=" + displayId
+                                + ", state=" + Display.stateToString(state) + ")");
                         try {
+                            final int mode = getPowerModeForState(state);
                             SurfaceControl.setDisplayPowerMode(token, mode);
                         } finally {
                             Trace.traceEnd(Trace.TRACE_TAG_POWER);
                         }
                     }
+
+                    private void setDisplayBrightness(int brightness) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "setDisplayBrightness("
+                                    + "id=" + displayId + ", brightness=" + brightness + ")");
+                        }
+
+                        Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness("
+                                + "id=" + displayId + ", brightness=" + brightness + ")");
+                        try {
+                            mBacklight.setBrightness(brightness);
+                        } finally {
+                            Trace.traceEnd(Trace.TRACE_TAG_POWER);
+                        }
+                    }
                 };
             }
             return null;
@@ -278,6 +357,8 @@
             pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
             pw.println("mPhys=" + mPhys);
             pw.println("mState=" + Display.stateToString(mState));
+            pw.println("mBrightness=" + mBrightness);
+            pw.println("mBacklight=" + mBacklight);
         }
 
         private void updateDeviceInfoLocked() {
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index f181cd5..6f59b54 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -221,7 +221,7 @@
         }
 
         @Override
-        public Runnable requestDisplayStateLocked(int state) {
+        public Runnable requestDisplayStateLocked(int state, int brightness) {
             if (state != mDisplayState) {
                 mDisplayState = state;
                 if (state == Display.STATE_OFF) {
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 2da9d8e..ed884ef 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -19,16 +19,11 @@
 import com.android.server.SystemService;
 
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.os.Handler;
-import android.os.IHardwareService;
 import android.os.Message;
 import android.os.Trace;
 import android.util.Slog;
 
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-
 public class LightsService extends SystemService {
     static final String TAG = "LightsService";
     static final boolean DEBUG = false;
@@ -124,46 +119,6 @@
         private boolean mFlashing;
     }
 
-    /* This class implements an obsolete API that was removed after eclair and re-added during the
-     * final moments of the froyo release to support flashlight apps that had been using the private
-     * IHardwareService API. This is expected to go away in the next release.
-     */
-    private final IHardwareService.Stub mLegacyFlashlightHack = new IHardwareService.Stub() {
-
-        private static final String FLASHLIGHT_FILE = "/sys/class/leds/spotlight/brightness";
-
-        public boolean getFlashlightEnabled() {
-            try {
-                FileInputStream fis = new FileInputStream(FLASHLIGHT_FILE);
-                int result = fis.read();
-                fis.close();
-                return (result != '0');
-            } catch (Exception e) {
-                return false;
-            }
-        }
-
-        public void setFlashlightEnabled(boolean on) {
-            final Context context = getContext();
-            if (context.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
-                    != PackageManager.PERMISSION_GRANTED &&
-                    context.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
-                    != PackageManager.PERMISSION_GRANTED) {
-                throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission");
-            }
-            try {
-                FileOutputStream fos = new FileOutputStream(FLASHLIGHT_FILE);
-                byte[] bytes = new byte[2];
-                bytes[0] = (byte)(on ? '1' : '0');
-                bytes[1] = '\n';
-                fos.write(bytes);
-                fos.close();
-            } catch (Exception e) {
-                // fail silently
-            }
-        }
-    };
-
     public LightsService(Context context) {
         super(context);
 
@@ -176,13 +131,12 @@
 
     @Override
     public void onStart() {
-        publishBinderService("hardware", mLegacyFlashlightHack);
         publishLocalService(LightsManager.class, mService);
     }
 
     private final LightsManager mService = new LightsManager() {
         @Override
-        public com.android.server.lights.Light getLight(int id) {
+        public Light getLight(int id) {
             if (id < LIGHT_ID_COUNT) {
                 return mLights[id];
             } else {