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

Commit a1d77ea9 authored by Zixuan Qu's avatar Zixuan Qu Committed by Android (Google) Code Review
Browse files

Merge "Specify language tag and layout type when creating virtual keyboard."

parents d66f254e 5892a47d
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -4716,13 +4716,19 @@ package android.hardware.input {
  public final class VirtualKeyboardConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
    method public int describeContents();
    method @NonNull public String getLanguageTag();
    method @NonNull public String getLayoutType();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualKeyboardConfig> CREATOR;
    field public static final String DEFAULT_LANGUAGE_TAG = "en-Latn-US";
    field public static final String DEFAULT_LAYOUT_TYPE = "qwerty";
  }
  public static final class VirtualKeyboardConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.Builder<android.hardware.input.VirtualKeyboardConfig.Builder> {
    ctor public VirtualKeyboardConfig.Builder();
    method @NonNull public android.hardware.input.VirtualKeyboardConfig build();
    method @NonNull public android.hardware.input.VirtualKeyboardConfig.Builder setLanguageTag(@NonNull String);
    method @NonNull public android.hardware.input.VirtualKeyboardConfig.Builder setLayoutType(@NonNull String);
  }
  public class VirtualMouse implements java.io.Closeable {
+89 −0
Original line number Diff line number Diff line
@@ -18,9 +18,12 @@ package android.hardware.input;

import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.icu.util.ULocale;
import android.os.Parcel;
import android.os.Parcelable;

import java.util.Objects;


/**
 * Configurations to create virtual keyboard.
@@ -29,6 +32,18 @@ import android.os.Parcelable;
 */
@SystemApi
public final class VirtualKeyboardConfig extends VirtualInputDeviceConfig implements Parcelable {
    /**
     * Default language tag when creating virtual keyboard. Used when the language tag is not set.
     */
    public static final String DEFAULT_LANGUAGE_TAG = "en-Latn-US";
    /** Default layout type when creating virtual keyboard. Used when the layout type is not set. */
    public static final String DEFAULT_LAYOUT_TYPE = "qwerty";

    @NonNull
    private final String mLanguageTag;

    @NonNull
    private final String mLayoutType;

    @NonNull
    public static final Creator<VirtualKeyboardConfig> CREATOR =
@@ -46,10 +61,30 @@ public final class VirtualKeyboardConfig extends VirtualInputDeviceConfig implem

    private VirtualKeyboardConfig(@NonNull Builder builder) {
        super(builder);
        mLanguageTag = builder.mLanguageTag;
        mLayoutType = builder.mLayoutType;
    }

    private VirtualKeyboardConfig(@NonNull Parcel in) {
        super(in);
        mLanguageTag = in.readString8();
        mLayoutType = in.readString8();
    }

    /**
     * @see Builder#setLanguageTag().
     */
    @NonNull
    public String getLanguageTag() {
        return mLanguageTag;
    }

    /**
     * @see Builder#setLayoutType().
     */
    @NonNull
    public String getLayoutType() {
        return mLayoutType;
    }

    @Override
@@ -60,12 +95,66 @@ public final class VirtualKeyboardConfig extends VirtualInputDeviceConfig implem
    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        super.writeToParcel(dest, flags);
        dest.writeString8(mLanguageTag);
        dest.writeString8(mLayoutType);
    }

    /**
     * Builder for creating a {@link VirtualKeyboardConfig}.
     */
    public static final class Builder extends VirtualInputDeviceConfig.Builder<Builder> {
        @NonNull
        private String mLanguageTag = DEFAULT_LANGUAGE_TAG;
        @NonNull
        private String mLayoutType = DEFAULT_LAYOUT_TYPE;

        /**
         * Sets the preferred input language of the virtual keyboard using an IETF
         * <a href="https://tools.ietf.org/html/bcp47">BCP-47</a>
         * conformant tag. See {@code keyboardLocale} attribute in
         * frameworks/base/packages/InputDevices/res/xml/keyboard_layouts.xml for a list of
         * supported language tags.
         *
         * The passed in {@code languageTag} will be canonized using {@link
         * ULocale} and used by the system as a hint to configure the keyboard layout.
         *
         * If {@code languageTag} is not specified, the virtual keyboard will be created with {@link
         * #DEFAULT_LANGUAGE_TAG}.
         *
         * Note that the preferred layout is not guaranteed. If the specified language is
         * well-formed but not supported, the keyboard will be using English US QWERTY layout.
         *
         *  @throws IllegalArgumentException if either of the language or country is not present in
         *  the language tag.
         */
        @NonNull
        public Builder setLanguageTag(@NonNull String languageTag) {
            Objects.requireNonNull(languageTag, "languageTag cannot be null");
            ULocale locale = ULocale.forLanguageTag(languageTag);
            if (locale.getLanguage().isEmpty() || locale.getCountry().isEmpty()) {
                throw new IllegalArgumentException("The language tag is not valid.");
            }
            mLanguageTag = ULocale.createCanonical(locale).toLanguageTag();
            return this;
        }

        /**
         * Sets the preferred layout type of the virtual keyboard. See {@code keyboardLayoutType}
         * attribute in frameworks/base/packages/InputDevices/res/xml/keyboard_layouts.xml for a
         * list of supported layout types.
         *
         * Note that the preferred layout is not guaranteed. If the specified layout type is
         * well-formed but not supported, the keyboard will be using English US QWERTY layout.
         *
         * If not specified, the virtual keyboard will be created with {@link #DEFAULT_LAYOUT_TYPE}.
         */
        @NonNull
        public Builder setLayoutType(@NonNull String layoutType) {
            Objects.requireNonNull(layoutType, "layoutType cannot be null");
            mLayoutType = layoutType;
            return this;
        }

        /**
         * Builds the {@link VirtualKeyboardConfig} instance.
         */
+76 −20
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.hardware.input.InputDeviceCountryCode;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.lights.LightsManager;
import android.icu.util.ULocale;
import android.os.Build;
import android.os.NullVibrator;
import android.os.Parcel;
@@ -76,6 +77,10 @@ public final class InputDevice implements Parcelable {
    private final KeyCharacterMap mKeyCharacterMap;
    @InputDeviceCountryCode
    private final int mCountryCode;
    @Nullable
    private final String mKeyboardLanguageTag;
    @Nullable
    private final String mKeyboardLayoutType;
    private final boolean mHasVibrator;
    private final boolean mHasMicrophone;
    private final boolean mHasButtonUnderPad;
@@ -464,6 +469,7 @@ public final class InputDevice implements Parcelable {
    private InputDevice(int id, int generation, int controllerNumber, String name, int vendorId,
            int productId, String descriptor, boolean isExternal, int sources, int keyboardType,
            KeyCharacterMap keyCharacterMap, @InputDeviceCountryCode int countryCode,
            @Nullable String keyboardLanguageTag, @Nullable String keyboardLayoutType,
            boolean hasVibrator, boolean hasMicrophone, boolean hasButtonUnderPad,
            boolean hasSensor, boolean hasBattery, boolean supportsUsi) {
        mId = id;
@@ -478,6 +484,14 @@ public final class InputDevice implements Parcelable {
        mKeyboardType = keyboardType;
        mKeyCharacterMap = keyCharacterMap;
        mCountryCode = countryCode;
        if (keyboardLanguageTag != null) {
            mKeyboardLanguageTag = ULocale
                    .createCanonical(ULocale.forLanguageTag(keyboardLanguageTag))
                    .toLanguageTag();
        } else {
            mKeyboardLanguageTag = null;
        }
        mKeyboardLayoutType = keyboardLayoutType;
        mHasVibrator = hasVibrator;
        mHasMicrophone = hasMicrophone;
        mHasButtonUnderPad = hasButtonUnderPad;
@@ -500,6 +514,8 @@ public final class InputDevice implements Parcelable {
        mSources = in.readInt();
        mKeyboardType = in.readInt();
        mCountryCode = in.readInt();
        mKeyboardLanguageTag = in.readString8();
        mKeyboardLayoutType = in.readString8();
        mHasVibrator = in.readInt() != 0;
        mHasMicrophone = in.readInt() != 0;
        mHasButtonUnderPad = in.readInt() != 0;
@@ -521,6 +537,7 @@ public final class InputDevice implements Parcelable {

    /**
     * InputDevice builder used to create an InputDevice for tests in Java.
     *
     * @hide
     */
    @VisibleForTesting
@@ -543,6 +560,8 @@ public final class InputDevice implements Parcelable {
        private boolean mHasBattery = false;
        @InputDeviceCountryCode
        private int mCountryCode = InputDeviceCountryCode.INVALID;
        private String mKeyboardLanguageTag = null;
        private String mKeyboardLayoutType = null;
        private boolean mSupportsUsi = false;

        /** @see InputDevice#getId() */
@@ -647,6 +666,18 @@ public final class InputDevice implements Parcelable {
            return this;
        }

        /** @see InputDevice#getKeyboardLanguageTag() */
        public Builder setKeyboardLanguageTag(String keyboardLanguageTag) {
            mKeyboardLanguageTag = keyboardLanguageTag;
            return this;
        }

        /** @see InputDevice#getKeyboardLayoutType() */
        public Builder setKeyboardLayoutType(String keyboardLayoutType) {
            mKeyboardLayoutType = keyboardLayoutType;
            return this;
        }

        /** @see InputDevice#supportsUsi() () */
        public Builder setSupportsUsi(boolean supportsUsi) {
            mSupportsUsi = supportsUsi;
@@ -657,8 +688,8 @@ public final class InputDevice implements Parcelable {
        public InputDevice build() {
            return new InputDevice(mId, mGeneration, mControllerNumber, mName, mVendorId,
                    mProductId, mDescriptor, mIsExternal, mSources, mKeyboardType, mKeyCharacterMap,
                    mCountryCode, mHasVibrator, mHasMicrophone, mHasButtonUnderPad, mHasSensor,
                    mHasBattery, mSupportsUsi);
                    mCountryCode, mKeyboardLanguageTag, mKeyboardLayoutType, mHasVibrator,
                    mHasMicrophone, mHasButtonUnderPad, mHasSensor, mHasBattery, mSupportsUsi);
        }
    }

@@ -887,8 +918,31 @@ public final class InputDevice implements Parcelable {
        return mCountryCode;
    }

    /**
     * Returns the keyboard language as an IETF
     * <a href="https://tools.ietf.org/html/bcp47">BCP-47</a>
     * conformant tag if available.
     *
     * @hide
     */
    @Nullable
    public String getKeyboardLanguageTag() {
        return mKeyboardLanguageTag;
    }

    /**
     * Returns the keyboard layout type if available.
     *
     * @hide
     */
    @Nullable
    public String getKeyboardLayoutType() {
        return mKeyboardLayoutType;
    }

    /**
     * Gets whether the device is capable of producing the list of keycodes.
     *
     * @param keys The list of android keycodes to check for.
     * @return An array of booleans where each member specifies whether the device is capable of
     * generating the keycode given by the corresponding value at the same index in the keys array.
@@ -1340,6 +1394,8 @@ public final class InputDevice implements Parcelable {
        out.writeInt(mSources);
        out.writeInt(mKeyboardType);
        out.writeInt(mCountryCode);
        out.writeString8(mKeyboardLanguageTag);
        out.writeString8(mKeyboardLayoutType);
        out.writeInt(mHasVibrator ? 1 : 0);
        out.writeInt(mHasMicrophone ? 1 : 0);
        out.writeInt(mHasButtonUnderPad ? 1 : 0);
+18 −5
Original line number Diff line number Diff line
@@ -48,6 +48,18 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi
        return NULL;
    }

    std::optional<KeyboardLayoutInfo> layoutInfo = deviceInfo.getKeyboardLayoutInfo();
    ScopedLocalRef<jstring> keyboardLanguageTagObj(env,
                                                   env->NewStringUTF(
                                                           layoutInfo
                                                                   ? layoutInfo->languageTag.c_str()
                                                                   : NULL));
    ScopedLocalRef<jstring> keyboardLayoutTypeObj(env,
                                                  env->NewStringUTF(
                                                          layoutInfo
                                                                  ? layoutInfo->layoutType.c_str()
                                                                  : NULL));

    ScopedLocalRef<jobject> kcmObj(env,
            android_view_KeyCharacterMap_create(env, deviceInfo.getId(),
            deviceInfo.getKeyCharacterMap()));
@@ -66,7 +78,8 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi
                                          static_cast<int32_t>(ident.product), descriptorObj.get(),
                                          deviceInfo.isExternal(), deviceInfo.getSources(),
                                          deviceInfo.getKeyboardType(), kcmObj.get(),
                                          deviceInfo.getCountryCode(), deviceInfo.hasVibrator(),
                                          deviceInfo.getCountryCode(), keyboardLanguageTagObj.get(),
                                          keyboardLayoutTypeObj.get(), deviceInfo.hasVibrator(),
                                          deviceInfo.hasMic(), deviceInfo.hasButtonUnderPad(),
                                          deviceInfo.hasSensor(), deviceInfo.hasBattery(),
                                          deviceInfo.supportsUsi()));
@@ -91,10 +104,10 @@ int register_android_view_InputDevice(JNIEnv* env)
    gInputDeviceClassInfo.clazz = FindClassOrDie(env, "android/view/InputDevice");
    gInputDeviceClassInfo.clazz = MakeGlobalRefOrDie(env, gInputDeviceClassInfo.clazz);

    gInputDeviceClassInfo.ctor =
            GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "<init>",
    gInputDeviceClassInfo.ctor = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "<init>",
                                                  "(IIILjava/lang/String;IILjava/lang/"
                             "String;ZIILandroid/view/KeyCharacterMap;IZZZZZZ)V");
                                                  "String;ZIILandroid/view/KeyCharacterMap;ILjava/"
                                                  "lang/String;Ljava/lang/String;ZZZZZZ)V");

    gInputDeviceClassInfo.addMotionRange = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz,
            "addMotionRange", "(IIFFFFF)V");
+13 −8
Original line number Diff line number Diff line
@@ -142,17 +142,18 @@ class InputController {
        }
    }

    void createKeyboard(@NonNull String deviceName,
            int vendorId,
            int productId,
            @NonNull IBinder deviceToken,
            int displayId) {
    void createKeyboard(@NonNull String deviceName, int vendorId, int productId,
            @NonNull IBinder deviceToken, int displayId, @NonNull String languageTag,
            @NonNull String layoutType) {
        final String phys = createPhys(PHYS_TYPE_KEYBOARD);
        mInputManagerInternal.addKeyboardLayoutAssociation(phys, languageTag,
                layoutType);
        try {
            createDeviceInternal(InputDeviceDescriptor.TYPE_KEYBOARD, deviceName, vendorId,
                    productId, deviceToken, displayId, phys,
                    () -> mNativeWrapper.openUinputKeyboard(deviceName, vendorId, productId, phys));
        } catch (DeviceCreationException e) {
            mInputManagerInternal.removeKeyboardLayoutAssociation(phys);
            throw new RuntimeException(
                    "Failed to create virtual keyboard device '" + deviceName + "'.", e);
        }
@@ -233,12 +234,16 @@ class InputController {
            InputDeviceDescriptor inputDeviceDescriptor) {
        token.unlinkToDeath(inputDeviceDescriptor.getDeathRecipient(), /* flags= */ 0);
        mNativeWrapper.closeUinput(inputDeviceDescriptor.getFileDescriptor());

        InputManager.getInstance().removeUniqueIdAssociation(inputDeviceDescriptor.getPhys());
        String phys = inputDeviceDescriptor.getPhys();
        InputManager.getInstance().removeUniqueIdAssociation(phys);
        // Type associations are added in the case of navigation touchpads. Those should be removed
        // once the input device gets closed.
        if (inputDeviceDescriptor.getType() == InputDeviceDescriptor.TYPE_NAVIGATION_TOUCHPAD) {
            mInputManagerInternal.unsetTypeAssociation(inputDeviceDescriptor.getPhys());
            mInputManagerInternal.unsetTypeAssociation(phys);
        }

        if (inputDeviceDescriptor.getType() == InputDeviceDescriptor.TYPE_KEYBOARD) {
            mInputManagerInternal.removeKeyboardLayoutAssociation(phys);
        }

        // Reset values to the default if all virtual mice are unregistered, or set display
Loading