Merge "Add TestApi to suppress other LightsSession clients" into sc-dev
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 0e6e8a5..5d51ff6 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1240,6 +1240,14 @@
 
 }
 
+package android.hardware.lights {
+
+  public abstract class LightsManager {
+    method @NonNull public abstract android.hardware.lights.LightsManager.LightsSession openSession(int);
+  }
+
+}
+
 package android.hardware.soundtrigger {
 
   public class KeyphraseEnrollmentInfo {
diff --git a/core/java/android/hardware/input/InputDeviceLightsManager.java b/core/java/android/hardware/input/InputDeviceLightsManager.java
index a3b91a9..885df7b 100644
--- a/core/java/android/hardware/input/InputDeviceLightsManager.java
+++ b/core/java/android/hardware/input/InputDeviceLightsManager.java
@@ -81,6 +81,11 @@
         return session;
     }
 
+    @Override
+    public @NonNull LightsSession openSession(int priority) {
+        throw new UnsupportedOperationException();
+    }
+
     /**
      * Encapsulates a session that can be used to control device lights and represents the lifetime
      * of the requests.
diff --git a/core/java/android/hardware/lights/ILightsManager.aidl b/core/java/android/hardware/lights/ILightsManager.aidl
index 6ea24b7..077797f 100644
--- a/core/java/android/hardware/lights/ILightsManager.aidl
+++ b/core/java/android/hardware/lights/ILightsManager.aidl
@@ -27,7 +27,7 @@
 interface ILightsManager {
   List<Light> getLights();
   LightState getLightState(int lightId);
-  void openSession(in IBinder sessionToken);
+  void openSession(in IBinder sessionToken, in int priority);
   void closeSession(in IBinder sessionToken);
   void setLightStates(in IBinder sessionToken, in int[] lightIds, in LightState[] states);
 }
diff --git a/core/java/android/hardware/lights/LightsManager.java b/core/java/android/hardware/lights/LightsManager.java
index 8fd56db..8bc86da 100644
--- a/core/java/android/hardware/lights/LightsManager.java
+++ b/core/java/android/hardware/lights/LightsManager.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
@@ -84,11 +85,24 @@
     public abstract @NonNull LightsSession openSession();
 
     /**
+     *
+     * Creates a new {@link LightsSession}
+     *
+     * @param priority the larger this number, the higher the priority of this session when multiple
+     *                 light state requests arrive simultaneously.
+     *
+     * @hide
+     */
+    @TestApi
+    public abstract @NonNull LightsSession openSession(int priority);
+
+    /**
      * Encapsulates a session that can be used to control device lights and represents the lifetime
      * of the requests.
      */
     public abstract static class LightsSession implements AutoCloseable {
         private final IBinder mToken = new Binder();
+
         /**
          * Sends a request to modify the states of multiple lights.
          *
diff --git a/core/java/android/hardware/lights/SystemLightsManager.java b/core/java/android/hardware/lights/SystemLightsManager.java
index 726a613..da034ee 100644
--- a/core/java/android/hardware/lights/SystemLightsManager.java
+++ b/core/java/android/hardware/lights/SystemLightsManager.java
@@ -102,7 +102,28 @@
     public @NonNull LightsSession openSession() {
         try {
             final LightsSession session = new SystemLightsSession();
-            mService.openSession(session.getToken());
+            mService.openSession(session.getToken(), 0);
+            return session;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     *
+     * Creates a new {@link LightsSession}
+     *
+     * @param priority the larger this number, the higher the priority of this session when multiple
+     *                 light state requests arrive simultaneously.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+    @Override
+    public @NonNull LightsSession openSession(int priority) {
+        try {
+            final LightsSession session = new SystemLightsSession();
+            mService.openSession(session.getToken(), priority);
             return session;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 42b0add..91f14de 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -46,6 +46,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -68,12 +69,14 @@
 
     private final class LightsManagerBinderService extends ILightsManager.Stub {
 
-        private final class Session {
+        private final class Session implements Comparable<Session> {
             final IBinder mToken;
             final SparseArray<LightState> mRequests = new SparseArray<>();
+            final int mPriority;
 
-            Session(IBinder token) {
+            Session(IBinder token, int priority) {
                 mToken = token;
+                mPriority = priority;
             }
 
             void setRequest(int lightId, LightState state) {
@@ -83,6 +86,12 @@
                     mRequests.remove(lightId);
                 }
             }
+
+            @Override
+            public int compareTo(Session otherSession) {
+                // Sort descending by priority
+                return Integer.compare(otherSession.mPriority, mPriority);
+            }
         }
 
         @GuardedBy("LightsService.this")
@@ -150,7 +159,7 @@
         }
 
         @Override
-        public void openSession(IBinder token) {
+        public void openSession(IBinder token, int priority) {
             getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
                     "openSession requires CONTROL_DEVICE_LIGHTS permission");
             Preconditions.checkNotNull(token);
@@ -159,7 +168,8 @@
                 Preconditions.checkState(getSessionLocked(token) == null, "already registered");
                 try {
                     token.linkToDeath(() -> closeSessionInternal(token), 0);
-                    mSessions.add(new Session(token));
+                    mSessions.add(new Session(token, priority));
+                    Collections.sort(mSessions);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Couldn't open session, client already died" , e);
                     throw new IllegalArgumentException("Client is already dead.");
@@ -216,10 +226,10 @@
         }
 
         private void checkRequestIsValid(int[] lightIds) {
-            for (int i = 0; i < lightIds.length; i++) {
-                final LightImpl light = mLightsById.get(lightIds[i]);
+            for (int lightId : lightIds) {
+                final LightImpl light = mLightsById.get(lightId);
                 Preconditions.checkState(light != null && !light.isSystemLight(),
-                        "Invalid lightId " + lightIds[i]);
+                        "Invalid lightId " + lightId);
             }
         }