Moved brightness from Lights to SF.

Test: manual.
      Check that brightness works.
Fixes: 111435292

Change-Id: I9351fcc69b3cc217e5eeb7bc3f813a41ba9dc547
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 5e2aaae..9740168 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -63,6 +63,7 @@
 import java.io.Closeable;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.Objects;
 
 /**
  * Handle to an on-screen Surface managed by the system compositor. The SurfaceControl is
@@ -196,6 +197,9 @@
     private static native boolean nativeGetProtectedContentSupport();
     private static native void nativeSetMetadata(long transactionObj, int key, Parcel data);
     private static native void nativeSyncInputWindows(long transactionObj);
+    private static native boolean nativeGetDisplayBrightnessSupport(IBinder displayToken);
+    private static native boolean nativeSetDisplayBrightness(IBinder displayToken,
+            float brightness);
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
     private String mName;
@@ -1958,6 +1962,47 @@
     }
 
     /**
+     * Returns whether brightness operations are supported on a display.
+     *
+     * @param displayToken
+     *      The token for the display.
+     *
+     * @return Whether brightness operations are supported on the display.
+     *
+     * @hide
+     */
+    public static boolean getDisplayBrightnessSupport(IBinder displayToken) {
+        return nativeGetDisplayBrightnessSupport(displayToken);
+    }
+
+    /**
+     * Sets the brightness of a display.
+     *
+     * @param displayToken
+     *      The token for the display whose brightness is set.
+     * @param brightness
+     *      A number between 0.0f (minimum brightness) and 1.0f (maximum brightness), or -1.0f to
+     *      turn the backlight off.
+     *
+     * @return Whether the method succeeded or not.
+     *
+     * @throws IllegalArgumentException if:
+     *      - displayToken is null;
+     *      - brightness is NaN or greater than 1.0f.
+     *
+     * @hide
+     */
+    public static boolean setDisplayBrightness(IBinder displayToken, float brightness) {
+        Objects.requireNonNull(displayToken);
+        if (Float.isNaN(brightness) || brightness > 1.0f
+                || (brightness < 0.0f && brightness != -1.0f)) {
+            throw new IllegalArgumentException("brightness must be a number between 0.0f and 1.0f,"
+                    + " or -1 to turn the backlight off.");
+        }
+        return nativeSetDisplayBrightness(displayToken, brightness);
+    }
+
+    /**
      * An atomic set of changes to a set of SurfaceControl.
      */
     public static class Transaction implements Closeable {
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 89d908b..4a6c72b 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1164,6 +1164,25 @@
     }
 }
 
+static jboolean nativeGetDisplayBrightnessSupport(JNIEnv* env, jclass clazz,
+        jobject displayTokenObject) {
+    sp<IBinder> displayToken(ibinderForJavaObject(env, displayTokenObject));
+    if (displayToken == nullptr) {
+        return JNI_FALSE;
+    }
+    return static_cast<jboolean>(SurfaceComposerClient::getDisplayBrightnessSupport(displayToken));
+}
+
+static jboolean nativeSetDisplayBrightness(JNIEnv* env, jclass clazz, jobject displayTokenObject,
+        jfloat brightness) {
+    sp<IBinder> displayToken(ibinderForJavaObject(env, displayTokenObject));
+    if (displayToken == nullptr) {
+        return JNI_FALSE;
+    }
+    status_t error = SurfaceComposerClient::setDisplayBrightness(displayToken, brightness);
+    return error == OK ? JNI_TRUE : JNI_FALSE;
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod sSurfaceControlMethods[] = {
@@ -1308,7 +1327,11 @@
     {"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V",
             (void*)nativeSetGeometry },
     {"nativeSyncInputWindows", "(J)V",
-            (void*)nativeSyncInputWindows }
+            (void*)nativeSyncInputWindows },
+    {"nativeGetDisplayBrightnessSupport", "(Landroid/os/IBinder;)Z",
+            (void*)nativeGetDisplayBrightnessSupport },
+    {"nativeSetDisplayBrightness", "(Landroid/os/IBinder;F)Z",
+            (void*)nativeSetDisplayBrightness },
 };
 
 int register_android_view_SurfaceControl(JNIEnv* env)
diff --git a/services/core/java/com/android/server/lights/Light.java b/services/core/java/com/android/server/lights/Light.java
index b5ec603..717e3da 100644
--- a/services/core/java/com/android/server/lights/Light.java
+++ b/services/core/java/com/android/server/lights/Light.java
@@ -16,8 +16,8 @@
 
 package com.android.server.lights;
 
-import android.hardware.light.V2_0.Flash;
 import android.hardware.light.V2_0.Brightness;
+import android.hardware.light.V2_0.Flash;
 
 public abstract class Light {
     public static final int LIGHT_FLASH_NONE = Flash.NONE;
@@ -39,8 +39,16 @@
      */
     public static final int BRIGHTNESS_MODE_LOW_PERSISTENCE = Brightness.LOW_PERSISTENCE;
 
+    /**
+     * Set the brightness of a display.
+     */
     public abstract void setBrightness(int brightness);
+
+    /**
+     * Set the brightness and mode of a display.
+     */
     public abstract void setBrightness(int brightness, int brightnessMode);
+
     public abstract void setColor(int color);
     public abstract void setFlashing(int color, int mode, int onMS, int offMS);
     public abstract void pulse();
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index a94ed60..ac906bb 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -15,15 +15,18 @@
 
 package com.android.server.lights;
 
-import com.android.server.SystemService;
-
 import android.app.ActivityManager;
 import android.content.Context;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
+import android.os.PowerManager;
 import android.os.Trace;
 import android.provider.Settings;
 import android.util.Slog;
+import android.view.SurfaceControl;
+
+import com.android.server.SystemService;
 
 public class LightsService extends SystemService {
     static final String TAG = "LightsService";
@@ -33,8 +36,25 @@
 
     private final class LightImpl extends Light {
 
-        private LightImpl(int id) {
+        private final IBinder mDisplayToken;
+        private final int mSurfaceControlMaximumBrightness;
+
+        private LightImpl(Context context, int id) {
             mId = id;
+            mDisplayToken = SurfaceControl.getInternalDisplayToken();
+            final boolean brightnessSupport = SurfaceControl.getDisplayBrightnessSupport(
+                    mDisplayToken);
+            if (DEBUG) {
+                Slog.d(TAG, "Display brightness support: " + brightnessSupport);
+            }
+            int maximumBrightness = 0;
+            if (brightnessSupport) {
+                PowerManager pm = context.getSystemService(PowerManager.class);
+                if (pm != null) {
+                    maximumBrightness = pm.getMaximumScreenBrightnessSetting();
+                }
+            }
+            mSurfaceControlMaximumBrightness = maximumBrightness;
         }
 
         @Override
@@ -51,10 +71,26 @@
                             ": brightness=0x" + Integer.toHexString(brightness));
                     return;
                 }
-
-                int color = brightness & 0x000000ff;
-                color = 0xff000000 | (color << 16) | (color << 8) | color;
-                setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
+                // Ideally, we'd like to set the brightness mode through the SF/HWC as well, but
+                // right now we just fall back to the old path through Lights brightessMode is
+                // anything but USER or the device shouldBeInLowPersistenceMode().
+                if (brightnessMode == BRIGHTNESS_MODE_USER && !shouldBeInLowPersistenceMode()
+                        && mSurfaceControlMaximumBrightness == 255) {
+                    // TODO: the last check should be mSurfaceControlMaximumBrightness != 0; the
+                    // reason we enforce 255 right now is to stay consistent with the old path. In
+                    // the future, the framework should be refactored so that brightness is a float
+                    // between 0.0f and 1.0f, and the actual number of supported brightness levels
+                    // is determined in the device-specific implementation.
+                    if (DEBUG) {
+                        Slog.d(TAG, "Using new setBrightness path!");
+                    }
+                    SurfaceControl.setDisplayBrightness(mDisplayToken,
+                            (float) brightness / mSurfaceControlMaximumBrightness);
+                } else {
+                    int color = brightness & 0x000000ff;
+                    color = 0xff000000 | (color << 16) | (color << 8) | color;
+                    setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
+                }
             }
         }
 
@@ -172,7 +208,7 @@
         super(context);
 
         for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
-            mLights[i] = new LightImpl(i);
+            mLights[i] = new LightImpl(context, i);
         }
     }