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

Commit fdf02585 authored by Prabir Pradhan's avatar Prabir Pradhan Committed by Android (Google) Code Review
Browse files

Merge changes from topic "inputdevice-supportsusi"

* changes:
  BatteryController: Only listen to UEvents from power_supply changes
  BatteryController: Remove the /sys prefix when adding UEvent listener
  Determine whether an input device supports USI using IDC files
parents 63db3419 9a5952a1
Loading
Loading
Loading
Loading
+24 −2
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ public final class InputDevice implements Parcelable {
    private final boolean mHasButtonUnderPad;
    private final boolean mHasSensor;
    private final boolean mHasBattery;
    private final boolean mSupportsUsi;
    private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();

    @GuardedBy("mMotionRanges")
@@ -462,7 +463,7 @@ public final class InputDevice implements Parcelable {
            int productId, String descriptor, boolean isExternal, int sources, int keyboardType,
            KeyCharacterMap keyCharacterMap, @InputDeviceCountryCode int countryCode,
            boolean hasVibrator, boolean hasMicrophone, boolean hasButtonUnderPad,
            boolean hasSensor, boolean hasBattery) {
            boolean hasSensor, boolean hasBattery, boolean supportsUsi) {
        mId = id;
        mGeneration = generation;
        mControllerNumber = controllerNumber;
@@ -481,6 +482,7 @@ public final class InputDevice implements Parcelable {
        mHasSensor = hasSensor;
        mHasBattery = hasBattery;
        mIdentifier = new InputDeviceIdentifier(descriptor, vendorId, productId);
        mSupportsUsi = supportsUsi;
    }

    private InputDevice(Parcel in) {
@@ -501,6 +503,7 @@ public final class InputDevice implements Parcelable {
        mHasButtonUnderPad = in.readInt() != 0;
        mHasSensor = in.readInt() != 0;
        mHasBattery = in.readInt() != 0;
        mSupportsUsi = in.readInt() != 0;
        mIdentifier = new InputDeviceIdentifier(mDescriptor, mVendorId, mProductId);

        int numRanges = in.readInt();
@@ -538,6 +541,7 @@ public final class InputDevice implements Parcelable {
        private boolean mHasBattery = false;
        @InputDeviceCountryCode
        private int mCountryCode = InputDeviceCountryCode.INVALID;
        private boolean mSupportsUsi = false;

        /** @see InputDevice#getId()  */
        public Builder setId(int id) {
@@ -641,12 +645,18 @@ public final class InputDevice implements Parcelable {
            return this;
        }

        /** @see InputDevice#supportsUsi() ()  */
        public Builder setSupportsUsi(boolean supportsUsi) {
            mSupportsUsi = supportsUsi;
            return this;
        }

        /** Build {@link InputDevice}. */
        public InputDevice build() {
            return new InputDevice(mId, mGeneration, mControllerNumber, mName, mVendorId,
                    mProductId, mDescriptor, mIsExternal, mSources, mKeyboardType, mKeyCharacterMap,
                    mCountryCode, mHasVibrator, mHasMicrophone, mHasButtonUnderPad, mHasSensor,
                    mHasBattery);
                    mHasBattery, mSupportsUsi);
        }
    }

@@ -1178,6 +1188,15 @@ public final class InputDevice implements Parcelable {
        return mHasBattery;
    }

    /**
     * Reports whether the device supports the Universal Stylus Initiative (USI) protocol for
     * styluses.
     * @hide
     */
    public boolean supportsUsi() {
        return mSupportsUsi;
    }

    /**
     * Provides information about the range of values for a particular {@link MotionEvent} axis.
     *
@@ -1308,6 +1327,7 @@ public final class InputDevice implements Parcelable {
        out.writeInt(mHasButtonUnderPad ? 1 : 0);
        out.writeInt(mHasSensor ? 1 : 0);
        out.writeInt(mHasBattery ? 1 : 0);
        out.writeInt(mSupportsUsi ? 1 : 0);

        final int numRanges = mMotionRanges.size();
        out.writeInt(numRanges);
@@ -1361,6 +1381,8 @@ public final class InputDevice implements Parcelable {

        description.append("  Has mic: ").append(mHasMicrophone).append("\n");

        description.append("  Supports USI: ").append(mSupportsUsi).append("\n");

        description.append("  Sources: 0x").append(Integer.toHexString(mSources)).append(" (");
        appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard");
        appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad");
+4 −6
Original line number Diff line number Diff line
@@ -57,9 +57,6 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi

    const InputDeviceIdentifier& ident = deviceInfo.getIdentifier();

    // Not sure why, but JNI is complaining when I pass this through directly.
    jboolean hasMic = deviceInfo.hasMic() ? JNI_TRUE : JNI_FALSE;

    ScopedLocalRef<jobject>
            inputDeviceObj(env,
                           env->NewObject(gInputDeviceClassInfo.clazz, gInputDeviceClassInfo.ctor,
@@ -70,8 +67,9 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi
                                          deviceInfo.isExternal(), deviceInfo.getSources(),
                                          deviceInfo.getKeyboardType(), kcmObj.get(),
                                          deviceInfo.getCountryCode(), deviceInfo.hasVibrator(),
                                          hasMic, deviceInfo.hasButtonUnderPad(),
                                          deviceInfo.hasSensor(), deviceInfo.hasBattery()));
                                          deviceInfo.hasMic(), deviceInfo.hasButtonUnderPad(),
                                          deviceInfo.hasSensor(), deviceInfo.hasBattery(),
                                          deviceInfo.supportsUsi()));

    const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
    for (const InputDeviceInfo::MotionRange& range: ranges) {
@@ -94,7 +92,7 @@ int register_android_view_InputDevice(JNIEnv* env)
    gInputDeviceClassInfo.ctor =
            GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "<init>",
                             "(IIILjava/lang/String;IILjava/lang/"
                             "String;ZIILandroid/view/KeyCharacterMap;IZZZZZ)V");
                             "String;ZIILandroid/view/KeyCharacterMap;IZZZZZZ)V");

    gInputDeviceClassInfo.addMotionRange = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz,
            "addMotionRange", "(IIFFFFF)V");
+25 −14
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ import android.view.InputDevice;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.input.BatteryController.UEventManager.UEventListener;
import com.android.server.input.BatteryController.UEventManager.UEventBatteryListener;

import java.io.PrintWriter;
import java.util.Arrays;
@@ -438,7 +438,7 @@ final class BatteryController {
        private State mState;

        @Nullable
        private UEventListener mUEventListener;
        private UEventBatteryListener mUEventBatteryListener;

        DeviceMonitor(int deviceId) {
            mState = new State(deviceId);
@@ -473,20 +473,26 @@ final class BatteryController {
                return;
            }
            final int deviceId = mState.deviceId;
            mUEventListener = new UEventListener() {
            mUEventBatteryListener = new UEventBatteryListener() {
                @Override
                public void onUEvent(long eventTime) {
                public void onBatteryUEvent(long eventTime) {
                    handleUEventNotification(deviceId, eventTime);
                }
            };
            mUEventManager.addListener(mUEventListener, "DEVPATH=" + batteryPath);
            mUEventManager.addListener(
                    mUEventBatteryListener, "DEVPATH=" + formatDevPath(batteryPath));
        }

        private String formatDevPath(String path) {
            // Remove the "/sys" prefix if it has one.
            return path.startsWith("/sys") ? path.substring(4) : path;
        }

        // This must be called when the device is no longer being monitored.
        public void stopMonitoring() {
            if (mUEventListener != null) {
                mUEventManager.removeListener(mUEventListener);
                mUEventListener = null;
            if (mUEventBatteryListener != null) {
                mUEventManager.removeListener(mUEventBatteryListener);
                mUEventBatteryListener = null;
            }
        }

@@ -498,7 +504,7 @@ final class BatteryController {
        @Override
        public String toString() {
            return "state=" + mState
                    + ", uEventListener=" + (mUEventListener != null ? "added" : "none");
                    + ", uEventListener=" + (mUEventBatteryListener != null ? "added" : "none");
        }
    }

@@ -507,7 +513,7 @@ final class BatteryController {
    interface UEventManager {

        @VisibleForTesting
        abstract class UEventListener {
        abstract class UEventBatteryListener {
            private final UEventObserver mObserver = new UEventObserver() {
                @Override
                public void onUEvent(UEvent event) {
@@ -517,18 +523,23 @@ final class BatteryController {
                                "UEventListener: Received UEvent: "
                                        + event + " eventTime: " + eventTime);
                    }
                    UEventListener.this.onUEvent(eventTime);
                    if (!"CHANGE".equalsIgnoreCase(event.get("ACTION"))
                            || !"POWER_SUPPLY".equalsIgnoreCase(event.get("SUBSYSTEM"))) {
                        // Disregard any UEvents that do not correspond to battery changes.
                        return;
                    }
                    UEventBatteryListener.this.onBatteryUEvent(eventTime);
                }
            };

            public abstract void onUEvent(long eventTime);
            public abstract void onBatteryUEvent(long eventTime);
        }

        default void addListener(UEventListener listener, String match) {
        default void addListener(UEventBatteryListener listener, String match) {
            listener.mObserver.startObserving(match);
        }

        default void removeListener(UEventListener listener) {
        default void removeListener(UEventBatteryListener listener) {
            listener.mObserver.stopObserving();
        }
    }
+10 −6
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.platform.test.annotations.Presubmit
import android.view.InputDevice
import androidx.test.InstrumentationRegistry
import com.android.server.input.BatteryController.UEventManager
import com.android.server.input.BatteryController.UEventManager.UEventBatteryListener
import org.hamcrest.Description
import org.hamcrest.Matcher
import org.hamcrest.MatcherAssert.assertThat
@@ -260,25 +261,28 @@ class BatteryControllerTests {

    @Test
    fun testListenersNotifiedOnUEventNotification() {
        `when`(native.getBatteryDevicePath(DEVICE_ID)).thenReturn("/test/device1")
        `when`(native.getBatteryDevicePath(DEVICE_ID)).thenReturn("/sys/dev/test/device1")
        `when`(native.getBatteryStatus(DEVICE_ID)).thenReturn(STATUS_CHARGING)
        `when`(native.getBatteryCapacity(DEVICE_ID)).thenReturn(78)
        val listener = createMockListener()
        val uEventListener = ArgumentCaptor.forClass(UEventManager.UEventListener::class.java)
        val uEventListener = ArgumentCaptor.forClass(UEventBatteryListener::class.java)
        batteryController.registerBatteryListener(DEVICE_ID, listener, PID)
        verify(uEventManager).addListener(uEventListener.capture(), eq("DEVPATH=/test/device1"))
        // The device paths for UEvent notifications do not include the "/sys" prefix, so verify
        // that the added listener is configured to match the path without that prefix.
        verify(uEventManager)
            .addListener(uEventListener.capture(), eq("DEVPATH=/dev/test/device1"))
        listener.verifyNotified(DEVICE_ID, status = STATUS_CHARGING, capacity = 0.78f)

        // If the battery state has changed when an UEvent is sent, the listeners are notified.
        `when`(native.getBatteryCapacity(DEVICE_ID)).thenReturn(80)
        uEventListener.value!!.onUEvent(TIMESTAMP)
        uEventListener.value!!.onBatteryUEvent(TIMESTAMP)
        listener.verifyNotified(DEVICE_ID, status = STATUS_CHARGING, capacity = 0.80f,
            eventTime = TIMESTAMP)

        // If the battery state has not changed when an UEvent is sent, the listeners are not
        // notified.
        clearInvocations(listener)
        uEventListener.value!!.onUEvent(TIMESTAMP + 1)
        uEventListener.value!!.onBatteryUEvent(TIMESTAMP + 1)
        verifyNoMoreInteractions(listener)

        batteryController.unregisterBatteryListener(DEVICE_ID, listener, PID)
@@ -293,7 +297,7 @@ class BatteryControllerTests {
        `when`(native.getBatteryStatus(DEVICE_ID)).thenReturn(STATUS_CHARGING)
        `when`(native.getBatteryCapacity(DEVICE_ID)).thenReturn(78)
        val listener = createMockListener()
        val uEventListener = ArgumentCaptor.forClass(UEventManager.UEventListener::class.java)
        val uEventListener = ArgumentCaptor.forClass(UEventBatteryListener::class.java)
        batteryController.registerBatteryListener(DEVICE_ID, listener, PID)
        verify(uEventManager).addListener(uEventListener.capture(), eq("DEVPATH=/test/device1"))
        listener.verifyNotified(DEVICE_ID, status = STATUS_CHARGING, capacity = 0.78f)
+1 −0
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ public class InputDeviceTest {
                .setHasSensor(true)
                .setHasBattery(true)
                .setCountryCode(InputDeviceCountryCode.INTERNATIONAL)
                .setSupportsUsi(true)
                .build();

        Parcel parcel = Parcel.obtain();