Add support to InputManagerService for listening to lid switch events.

This extracts the notifyLidSwitchChanged() method from
WindowManagerCallbacks to allow services other than window manager to
receive lid switch notifications

Test: Manual, register callback and trigger lid switch
Bug: 159401801

Change-Id: I8967d4f2f5a9c56c2b7e0822224d1c0ea0f1bc06
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
index f6cd726..1173c31 100644
--- a/core/java/android/hardware/input/InputManagerInternal.java
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -78,4 +78,26 @@
      */
     public abstract boolean transferTouchFocus(@NonNull IBinder fromChannelToken,
             @NonNull IBinder toChannelToken);
+
+    /** Registers the {@link LidSwitchCallback} to begin receiving notifications. */
+    public abstract void registerLidSwitchCallback(@NonNull LidSwitchCallback callbacks);
+
+    /**
+     * Unregisters a {@link LidSwitchCallback callback} previously registered with
+     * {@link #registerLidSwitchCallback(LidSwitchCallback)}.
+     */
+    public abstract void unregisterLidSwitchCallback(@NonNull LidSwitchCallback callbacks);
+
+    /** Callback interface for notifications relating to the lid switch. */
+    public interface LidSwitchCallback {
+        /**
+         * This callback is invoked when the lid switch changes state. Will be triggered once on
+         * registration of the callback with a {@code whenNanos} of 0 and then on every subsequent
+         * change in lid switch state.
+         *
+         * @param whenNanos the time when the change occurred
+         * @param lidOpen true if the lid is open
+         */
+        void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
+    }
 }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 7c98c6c..fa50bac0 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -46,6 +46,7 @@
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
 import android.hardware.input.InputManagerInternal;
+import android.hardware.input.InputManagerInternal.LidSwitchCallback;
 import android.hardware.input.KeyboardLayout;
 import android.hardware.input.TouchCalibration;
 import android.media.AudioManager;
@@ -189,6 +190,10 @@
     private Map<IBinder, VibratorToken> mVibratorTokens = new ArrayMap<IBinder, VibratorToken>();
     private int mNextVibratorTokenValue;
 
+    // State for lid switch
+    private final Object mLidSwitchLock = new Object();
+    private List<LidSwitchCallback> mLidSwitchCallbacks = new ArrayList<>();
+
     // State for the currently installed input filter.
     final Object mInputFilterLock = new Object();
     IInputFilter mInputFilter; // guarded by mInputFilterLock
@@ -330,6 +335,9 @@
     public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
     public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE;
 
+    /** Indicates an open state for the lid switch. */
+    public static final int SW_STATE_LID_OPEN = 0;
+
     /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
     final boolean mUseDevInputEventForAudioJack;
 
@@ -353,13 +361,33 @@
     }
 
     public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
+        if (mWindowManagerCallbacks != null) {
+            unregisterLidSwitchCallbackInternal(mWindowManagerCallbacks);
+        }
         mWindowManagerCallbacks = callbacks;
+        registerLidSwitchCallbackInternal(mWindowManagerCallbacks);
     }
 
     public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
         mWiredAccessoryCallbacks = callbacks;
     }
 
+    void registerLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) {
+        boolean lidOpen;
+        synchronized (mLidSwitchLock) {
+            mLidSwitchCallbacks.add(callback);
+            lidOpen = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID)
+                    == SW_STATE_LID_OPEN;
+        }
+        callback.notifyLidSwitchChanged(0 /* whenNanos */, lidOpen);
+    }
+
+    void unregisterLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) {
+        synchronized (mLidSwitchLock) {
+            mLidSwitchCallbacks.remove(callback);
+        }
+    }
+
     public void start() {
         Slog.i(TAG, "Starting input manager");
         nativeStart(mPtr);
@@ -1934,6 +1962,7 @@
         synchronized (mInputFilterLock) { }
         synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
         synchronized (mGestureMonitorPidsLock) { /* Test if blocked by gesture monitor pids lock */}
+        synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ }
         nativeMonitor(mPtr);
     }
 
@@ -1964,7 +1993,15 @@
 
         if ((switchMask & SW_LID_BIT) != 0) {
             final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
-            mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
+
+            ArrayList<LidSwitchCallback> callbacksCopy;
+            synchronized (mLidSwitchLock) {
+                callbacksCopy = new ArrayList<>(mLidSwitchCallbacks);
+            }
+            for (int i = 0; i < callbacksCopy.size(); i++) {
+                LidSwitchCallback callbacks = callbacksCopy.get(i);
+                callbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
+            }
         }
 
         if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
@@ -2263,20 +2300,13 @@
     /**
      * Callback interface implemented by the Window Manager.
      */
-    public interface WindowManagerCallbacks {
+    public interface WindowManagerCallbacks extends LidSwitchCallback {
         /**
          * This callback is invoked when the confuguration changes.
          */
         public void notifyConfigurationChanged();
 
         /**
-         * This callback is invoked when the lid switch changes state.
-         * @param whenNanos the time when the change occurred
-         * @param lidOpen true if the lid is open
-         */
-        public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
-
-        /**
          * This callback is invoked when the camera lens cover switch changes state.
          * @param whenNanos the time when the change occurred
          * @param lensCovered true is the lens is covered
@@ -2603,6 +2633,16 @@
                 @NonNull IBinder toChannelToken) {
             return InputManagerService.this.transferTouchFocus(fromChannelToken, toChannelToken);
         }
+
+        @Override
+        public void registerLidSwitchCallback(LidSwitchCallback callbacks) {
+            registerLidSwitchCallbackInternal(callbacks);
+        }
+
+        @Override
+        public void unregisterLidSwitchCallback(LidSwitchCallback callbacks) {
+            unregisterLidSwitchCallbackInternal(callbacks);
+        }
     }
 
     @Override