diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index 6314cabd298dd..222cf080379c1 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -22,6 +22,8 @@ import android.hardware.input.KeyboardLayout; import android.hardware.input.IInputDevicesChangedListener; import android.hardware.input.IInputDeviceBatteryListener; import android.hardware.input.IInputDeviceBatteryState; +import android.hardware.input.IKeyboardBacklightListener; +import android.hardware.input.IKeyboardBacklightState; import android.hardware.input.ITabletModeChangedListener; import android.hardware.input.TouchCalibration; import android.os.CombinedVibration; @@ -221,4 +223,14 @@ interface IInputManager { @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + "android.Manifest.permission.MONITOR_INPUT)") void pilferPointers(IBinder inputChannelToken); + + @EnforcePermission("MONITOR_KEYBOARD_BACKLIGHT") + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + + "android.Manifest.permission.MONITOR_KEYBOARD_BACKLIGHT)") + void registerKeyboardBacklightListener(IKeyboardBacklightListener listener); + + @EnforcePermission("MONITOR_KEYBOARD_BACKLIGHT") + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + + "android.Manifest.permission.MONITOR_KEYBOARD_BACKLIGHT)") + void unregisterKeyboardBacklightListener(IKeyboardBacklightListener listener); } diff --git a/core/java/android/hardware/input/IKeyboardBacklightListener.aidl b/core/java/android/hardware/input/IKeyboardBacklightListener.aidl new file mode 100644 index 0000000000000..2c1f2520350d8 --- /dev/null +++ b/core/java/android/hardware/input/IKeyboardBacklightListener.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.input; + +import android.hardware.input.IKeyboardBacklightState; + +/** @hide */ +oneway interface IKeyboardBacklightListener { + + /** + * Called when the keyboard backlight brightness is changed. + */ + void onBrightnessChanged(int deviceId, in IKeyboardBacklightState state, boolean isTriggeredByKeyPress); +} diff --git a/core/java/android/hardware/input/IKeyboardBacklightState.aidl b/core/java/android/hardware/input/IKeyboardBacklightState.aidl new file mode 100644 index 0000000000000..b04aa66d3e81d --- /dev/null +++ b/core/java/android/hardware/input/IKeyboardBacklightState.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.input; + +/** @hide */ +@JavaDerive(equals=true) +parcelable IKeyboardBacklightState { + /** Current brightness level of the keyboard backlight in the range [0, maxBrightnessLevel]*/ + int brightnessLevel; + + /** Maximum brightness level of keyboard backlight */ + int maxBrightnessLevel; +} \ No newline at end of file diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 655e5981971fa..fb201cfbbe38d 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -119,6 +119,12 @@ public final class InputManager { @GuardedBy("mBatteryListenersLock") private IInputDeviceBatteryListener mInputDeviceBatteryListener; + private final Object mKeyboardBacklightListenerLock = new Object(); + @GuardedBy("mKeyboardBacklightListenerLock") + private List mKeyboardBacklightListeners; + @GuardedBy("mKeyboardBacklightListenerLock") + private IKeyboardBacklightListener mKeyboardBacklightListener; + private InputDeviceSensorManager mInputDeviceSensorManager; /** * Broadcast Action: Query available keyboard layouts. @@ -2280,6 +2286,74 @@ public final class InputManager { // TODO: set the right setting } + /** + * Registers a Keyboard backlight change listener to be notified about {@link + * KeyboardBacklightState} changes for connected keyboard devices. + * + * @param executor an executor on which the callback will be called + * @param listener the {@link KeyboardBacklightListener} + * @hide + * @see #unregisterKeyboardBacklightListener(KeyboardBacklightListener) + * @throws IllegalArgumentException if {@code listener} has already been registered previously. + * @throws NullPointerException if {@code listener} or {@code executor} is null. + */ + @RequiresPermission(Manifest.permission.MONITOR_KEYBOARD_BACKLIGHT) + public void registerKeyboardBacklightListener(@NonNull Executor executor, + @NonNull KeyboardBacklightListener listener) throws IllegalArgumentException { + Objects.requireNonNull(executor, "executor should not be null"); + Objects.requireNonNull(listener, "listener should not be null"); + + synchronized (mKeyboardBacklightListenerLock) { + if (mKeyboardBacklightListener == null) { + mKeyboardBacklightListeners = new ArrayList<>(); + mKeyboardBacklightListener = new LocalKeyboardBacklightListener(); + + try { + mIm.registerKeyboardBacklightListener(mKeyboardBacklightListener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + for (KeyboardBacklightListenerDelegate delegate : mKeyboardBacklightListeners) { + if (delegate.mListener == listener) { + throw new IllegalArgumentException("Listener has already been registered!"); + } + } + KeyboardBacklightListenerDelegate delegate = + new KeyboardBacklightListenerDelegate(listener, executor); + mKeyboardBacklightListeners.add(delegate); + } + } + + /** + * Unregisters a previously added Keyboard backlight change listener. + * + * @param listener the {@link KeyboardBacklightListener} + * @see #registerKeyboardBacklightListener(Executor, KeyboardBacklightListener) + * @hide + */ + @RequiresPermission(Manifest.permission.MONITOR_KEYBOARD_BACKLIGHT) + public void unregisterKeyboardBacklightListener( + @NonNull KeyboardBacklightListener listener) { + Objects.requireNonNull(listener, "listener should not be null"); + + synchronized (mKeyboardBacklightListenerLock) { + if (mKeyboardBacklightListeners == null) { + return; + } + mKeyboardBacklightListeners.removeIf((delegate) -> delegate.mListener == listener); + if (mKeyboardBacklightListeners.isEmpty()) { + try { + mIm.unregisterKeyboardBacklightListener(mKeyboardBacklightListener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + mKeyboardBacklightListeners = null; + mKeyboardBacklightListener = null; + } + } + } + /** * A callback used to be notified about battery state changes for an input device. The * {@link #onBatteryStateChanged(int, long, BatteryState)} method will be called once after the @@ -2373,6 +2447,27 @@ public final class InputManager { void onTabletModeChanged(long whenNanos, boolean inTabletMode); } + /** + * A callback used to be notified about keyboard backlight state changes for keyboard device. + * The {@link #onKeyboardBacklightChanged(int, KeyboardBacklightState, boolean)} method + * will be called once after the listener is successfully registered to provide the initial + * keyboard backlight state of the device. + * @see #registerKeyboardBacklightListener(Executor, KeyboardBacklightListener) + * @see #unregisterKeyboardBacklightListener(KeyboardBacklightListener) + * @hide + */ + public interface KeyboardBacklightListener { + /** + * Called when the keyboard backlight brightness level changes. + * @param deviceId the keyboard for which the backlight brightness changed. + * @param state the new keyboard backlight state, never null. + * @param isTriggeredByKeyPress whether brightness change was triggered by the user + * pressing up/down key on the keyboard. + */ + void onKeyboardBacklightChanged( + int deviceId, @NonNull KeyboardBacklightState state, boolean isTriggeredByKeyPress); + } + private final class TabletModeChangedListener extends ITabletModeChangedListener.Stub { @Override public void onTabletModeChanged(long whenNanos, boolean inTabletMode) { @@ -2481,4 +2576,59 @@ public final class InputManager { } } } + + // Implementation of the android.hardware.input.KeyboardBacklightState interface used to report + // the keyboard backlight state via the KeyboardBacklightListener interfaces. + private static final class LocalKeyboardBacklightState extends KeyboardBacklightState { + + private final int mBrightnessLevel; + private final int mMaxBrightnessLevel; + + LocalKeyboardBacklightState(int brightnesslevel, int maxBrightnessLevel) { + mBrightnessLevel = brightnesslevel; + mMaxBrightnessLevel = maxBrightnessLevel; + } + + @Override + public int getBrightnessLevel() { + return mBrightnessLevel; + } + + @Override + public int getMaxBrightnessLevel() { + return mMaxBrightnessLevel; + } + } + + private static final class KeyboardBacklightListenerDelegate { + final KeyboardBacklightListener mListener; + final Executor mExecutor; + + KeyboardBacklightListenerDelegate(KeyboardBacklightListener listener, Executor executor) { + mListener = listener; + mExecutor = executor; + } + + void notifyKeyboardBacklightChange(int deviceId, IKeyboardBacklightState state, + boolean isTriggeredByKeyPress) { + mExecutor.execute(() -> + mListener.onKeyboardBacklightChanged(deviceId, + new LocalKeyboardBacklightState(state.brightnessLevel, + state.maxBrightnessLevel), isTriggeredByKeyPress)); + } + } + + private class LocalKeyboardBacklightListener extends IKeyboardBacklightListener.Stub { + + @Override + public void onBrightnessChanged(int deviceId, IKeyboardBacklightState state, + boolean isTriggeredByKeyPress) { + synchronized (mKeyboardBacklightListenerLock) { + if (mKeyboardBacklightListeners == null) return; + for (KeyboardBacklightListenerDelegate delegate : mKeyboardBacklightListeners) { + delegate.notifyKeyboardBacklightChange(deviceId, state, isTriggeredByKeyPress); + } + } + } + } } diff --git a/core/java/android/hardware/input/KeyboardBacklightState.java b/core/java/android/hardware/input/KeyboardBacklightState.java new file mode 100644 index 0000000000000..4beaf6d36d7fc --- /dev/null +++ b/core/java/android/hardware/input/KeyboardBacklightState.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.input; + +/** + * The KeyboardBacklightState class is a representation of a keyboard backlight which is a + * single-colored backlight that illuminates all the keys on the keyboard. + * + * @hide + */ +public abstract class KeyboardBacklightState { + + /** + * Get the backlight brightness level in range [0, {@link #getMaxBrightnessLevel()}]. + * + * @return backlight brightness level + */ + public abstract int getBrightnessLevel(); + + /** + * Get the max backlight brightness level. + * + * @return max backlight brightness level + */ + public abstract int getMaxBrightnessLevel(); +} + diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 5f1a444d6cf62..fed812ebf3908 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -6855,6 +6855,12 @@ + + +