Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c1620635 authored by Josep del Río's avatar Josep del Río Committed by Android (Google) Code Review
Browse files

Merge "Add mic mute keyboard led. (1/2)" into main

parents 612e6399 0d88649d
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -64,6 +64,12 @@ public final class Light implements Parcelable {
     */
     */
    public static final int LIGHT_TYPE_KEYBOARD_BACKLIGHT = 10003;
    public static final int LIGHT_TYPE_KEYBOARD_BACKLIGHT = 10003;


    /**
     * Type for keyboard microphone mute light.
     * @hide
     */
    public static final int LIGHT_TYPE_KEYBOARD_MIC_MUTE = 10004;

    /**
    /**
     * Capability for lights that could adjust its LED brightness. If the capability is not present
     * Capability for lights that could adjust its LED brightness. If the capability is not present
     * the LED can only be turned either on or off.
     * the LED can only be turned either on or off.
@@ -92,6 +98,7 @@ public final class Light implements Parcelable {
            LIGHT_TYPE_INPUT,
            LIGHT_TYPE_INPUT,
            LIGHT_TYPE_PLAYER_ID,
            LIGHT_TYPE_PLAYER_ID,
            LIGHT_TYPE_KEYBOARD_BACKLIGHT,
            LIGHT_TYPE_KEYBOARD_BACKLIGHT,
            LIGHT_TYPE_KEYBOARD_MIC_MUTE,
        })
        })
    public @interface LightType {}
    public @interface LightType {}


+7 −0
Original line number Original line Diff line number Diff line
@@ -330,6 +330,9 @@ public class InputManagerService extends IInputManager.Stub
    // Manages Sticky modifier state
    // Manages Sticky modifier state
    private final StickyModifierStateController mStickyModifierStateController;
    private final StickyModifierStateController mStickyModifierStateController;


    // Manages Keyboard microphone mute led
    private final KeyboardLedController mKeyboardLedController;

    // Manages Keyboard modifier keys remapping
    // Manages Keyboard modifier keys remapping
    private final KeyRemapper mKeyRemapper;
    private final KeyRemapper mKeyRemapper;


@@ -479,6 +482,8 @@ public class InputManagerService extends IInputManager.Stub
                        injector.getLooper(), injector.getUEventManager())
                        injector.getLooper(), injector.getUEventManager())
                : new KeyboardBacklightControllerInterface() {};
                : new KeyboardBacklightControllerInterface() {};
        mStickyModifierStateController = new StickyModifierStateController();
        mStickyModifierStateController = new StickyModifierStateController();
        mKeyboardLedController = new KeyboardLedController(mContext, injector.getLooper(),
                mNative);
        mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper());
        mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper());
        mPointerIconCache = new PointerIconCache(mContext, mNative);
        mPointerIconCache = new PointerIconCache(mContext, mNative);


@@ -593,6 +598,7 @@ public class InputManagerService extends IInputManager.Stub
        mKeyboardLayoutManager.systemRunning();
        mKeyboardLayoutManager.systemRunning();
        mBatteryController.systemRunning();
        mBatteryController.systemRunning();
        mKeyboardBacklightController.systemRunning();
        mKeyboardBacklightController.systemRunning();
        mKeyboardLedController.systemRunning();
        mKeyRemapper.systemRunning();
        mKeyRemapper.systemRunning();
        mPointerIconCache.systemRunning();
        mPointerIconCache.systemRunning();
    }
    }
@@ -2218,6 +2224,7 @@ public class InputManagerService extends IInputManager.Stub
        dumpDisplayInputPropertiesValues(ipw);
        dumpDisplayInputPropertiesValues(ipw);
        mBatteryController.dump(ipw);
        mBatteryController.dump(ipw);
        mKeyboardBacklightController.dump(ipw);
        mKeyboardBacklightController.dump(ipw);
        mKeyboardLedController.dump(ipw);
    }
    }


    private void dumpAssociations(IndentingPrintWriter pw) {
    private void dumpAssociations(IndentingPrintWriter pw) {
+171 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright 2024 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 com.android.server.input;

import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.hardware.SensorPrivacyManager;
import android.hardware.SensorPrivacyManager.Sensors;
import android.hardware.input.InputManager;
import android.hardware.lights.Light;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.UserHandle;
import android.util.IndentingPrintWriter;
import android.util.SparseArray;
import android.view.InputDevice;

import java.io.PrintWriter;
import java.util.Objects;

/**
 * This class is used to control the light of keyboard.
 */
public final class KeyboardLedController implements InputManager.InputDeviceListener {

    private static final String TAG = KeyboardLedController.class.getSimpleName();
    private static final int MSG_UPDATE_EXISTING_DEVICES = 1;
    private static final int MSG_UPDATE_MIC_MUTE_LED_STATE = 2;

    private final Context mContext;
    private final Handler mHandler;
    private final NativeInputManagerService mNative;
    private final SparseArray<InputDevice> mKeyboardsWithMicMuteLed = new SparseArray<>();
    @NonNull
    private InputManager mInputManager;
    @NonNull
    private SensorPrivacyManager mSensorPrivacyManager;
    @NonNull
    private AudioManager mAudioManager;
    private BroadcastReceiver mMicrophoneMuteChangedIntentReceiver =
            new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    Message msg =  Message.obtain(mHandler, MSG_UPDATE_MIC_MUTE_LED_STATE);
                    mHandler.sendMessage(msg);
                }
            };

    KeyboardLedController(Context context, Looper looper,
            NativeInputManagerService nativeService) {
        mContext = context;
        mNative = nativeService;
        mHandler = new Handler(looper, this::handleMessage);
    }

    private boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_UPDATE_EXISTING_DEVICES:
                for (int deviceId : (int[]) msg.obj) {
                    onInputDeviceAdded(deviceId);
                }
                return true;
            case MSG_UPDATE_MIC_MUTE_LED_STATE:
                updateMicMuteLedState();
                return true;
        }
        return false;
    }

    private void updateMicMuteLedState() {
        // We determine if the microphone is muted by querying both the hardware state of the
        // microphone and the microphone sensor privacy hardware and sensor toggles
        boolean isMicrophoneMute = mAudioManager.isMicrophoneMute()
                || mSensorPrivacyManager.areAnySensorPrivacyTogglesEnabled(Sensors.MICROPHONE);
        int color = isMicrophoneMute ? Color.WHITE : Color.TRANSPARENT;
        for (int i = 0; i < mKeyboardsWithMicMuteLed.size(); i++) {
            InputDevice device = mKeyboardsWithMicMuteLed.valueAt(i);
            if (device != null) {
                int deviceId = device.getId();
                Light light = getKeyboardMicMuteLight(device);
                if (light != null) {
                    mNative.setLightColor(deviceId, light.getId(), color);
                }
            }
        }
    }

    private Light getKeyboardMicMuteLight(InputDevice device) {
        for (Light light : device.getLightsManager().getLights()) {
            if (light.getType() == Light.LIGHT_TYPE_KEYBOARD_MIC_MUTE
                    && light.hasBrightnessControl()) {
                return light;
            }
        }
        return null;
    }

    /** Called when the system is ready for us to start third-party code. */
    public void systemRunning() {
        mSensorPrivacyManager = Objects.requireNonNull(
                mContext.getSystemService(SensorPrivacyManager.class));
        mInputManager = Objects.requireNonNull(mContext.getSystemService(InputManager.class));
        mAudioManager = Objects.requireNonNull(mContext.getSystemService(AudioManager.class));
        mInputManager.registerInputDeviceListener(this, mHandler);
        Message msg = Message.obtain(mHandler, MSG_UPDATE_EXISTING_DEVICES,
                mInputManager.getInputDeviceIds());
        mHandler.sendMessage(msg);
        mContext.registerReceiverAsUser(
                mMicrophoneMuteChangedIntentReceiver,
                UserHandle.ALL,
                new IntentFilter(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED),
                null,
                mHandler);
    }

    @Override
    public void onInputDeviceAdded(int deviceId) {
        onInputDeviceChanged(deviceId);
    }

    @Override
    public void onInputDeviceRemoved(int deviceId) {
        mKeyboardsWithMicMuteLed.remove(deviceId);
    }

    @Override
    public void onInputDeviceChanged(int deviceId) {
        InputDevice inputDevice = mInputManager.getInputDevice(deviceId);
        if (inputDevice == null) {
            return;
        }
        if (getKeyboardMicMuteLight(inputDevice) != null) {
            mKeyboardsWithMicMuteLed.put(deviceId, inputDevice);
            Message msg = Message.obtain(mHandler, MSG_UPDATE_MIC_MUTE_LED_STATE);
            mHandler.sendMessage(msg);
        }
    }

    /** Dump the diagnostic information */
    public void dump(PrintWriter pw) {
        IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
        ipw.println(TAG + ": " + mKeyboardsWithMicMuteLed.size() + " keyboard mic mute lights");
        ipw.increaseIndent();
        for (int i = 0; i < mKeyboardsWithMicMuteLed.size(); i++) {
            InputDevice inputDevice = mKeyboardsWithMicMuteLed.valueAt(i);
            ipw.println(i + " " + inputDevice.getName() + ": "
                    + getKeyboardMicMuteLight(inputDevice).toString());
        }
        ipw.decreaseIndent();
    }
}
+6 −0
Original line number Original line Diff line number Diff line
@@ -178,6 +178,7 @@ static struct {
    jfieldID lightTypeInput;
    jfieldID lightTypeInput;
    jfieldID lightTypePlayerId;
    jfieldID lightTypePlayerId;
    jfieldID lightTypeKeyboardBacklight;
    jfieldID lightTypeKeyboardBacklight;
    jfieldID lightTypeKeyboardMicMute;
    jfieldID lightCapabilityBrightness;
    jfieldID lightCapabilityBrightness;
    jfieldID lightCapabilityColorRgb;
    jfieldID lightCapabilityColorRgb;
} gLightClassInfo;
} gLightClassInfo;
@@ -2432,6 +2433,9 @@ static jobject nativeGetLights(JNIEnv* env, jobject nativeImplObj, jint deviceId
        } else if (lightInfo.type == InputDeviceLightType::KEYBOARD_BACKLIGHT) {
        } else if (lightInfo.type == InputDeviceLightType::KEYBOARD_BACKLIGHT) {
            jTypeId = env->GetStaticIntField(gLightClassInfo.clazz,
            jTypeId = env->GetStaticIntField(gLightClassInfo.clazz,
                                             gLightClassInfo.lightTypeKeyboardBacklight);
                                             gLightClassInfo.lightTypeKeyboardBacklight);
        } else if (lightInfo.type == InputDeviceLightType::KEYBOARD_MIC_MUTE) {
            jTypeId = env->GetStaticIntField(gLightClassInfo.clazz,
                                             gLightClassInfo.lightTypeKeyboardMicMute);
        } else {
        } else {
            ALOGW("Unknown light type %d", lightInfo.type);
            ALOGW("Unknown light type %d", lightInfo.type);
            continue;
            continue;
@@ -3165,6 +3169,8 @@ int register_android_server_InputManager(JNIEnv* env) {
            env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_TYPE_PLAYER_ID", "I");
            env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_TYPE_PLAYER_ID", "I");
    gLightClassInfo.lightTypeKeyboardBacklight =
    gLightClassInfo.lightTypeKeyboardBacklight =
            env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_TYPE_KEYBOARD_BACKLIGHT", "I");
            env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_TYPE_KEYBOARD_BACKLIGHT", "I");
    gLightClassInfo.lightTypeKeyboardMicMute =
            env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_TYPE_KEYBOARD_MIC_MUTE", "I");
    gLightClassInfo.lightCapabilityBrightness =
    gLightClassInfo.lightCapabilityBrightness =
            env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_CAPABILITY_BRIGHTNESS", "I");
            env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_CAPABILITY_BRIGHTNESS", "I");
    gLightClassInfo.lightCapabilityColorRgb =
    gLightClassInfo.lightCapabilityColorRgb =
+2 −1
Original line number Original line Diff line number Diff line
@@ -30,7 +30,7 @@ android_test {
        "androidx.test.rules",
        "androidx.test.rules",
        "androidx.test.runner",
        "androidx.test.runner",
        "androidx.test.uiautomator_uiautomator",
        "androidx.test.uiautomator_uiautomator",
        "servicestests-utils",
        "compatibility-device-util-axt",
        "flag-junit",
        "flag-junit",
        "frameworks-base-testutils",
        "frameworks-base-testutils",
        "hamcrest-library",
        "hamcrest-library",
@@ -38,6 +38,7 @@ android_test {
        "mockito-target-minus-junit4",
        "mockito-target-minus-junit4",
        "platform-test-annotations",
        "platform-test-annotations",
        "services.core.unboosted",
        "services.core.unboosted",
        "servicestests-utils",
        "testables",
        "testables",
        "testng",
        "testng",
        "truth",
        "truth",
Loading