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

Commit dd885d9e authored by Vaibhav Devmurari's avatar Vaibhav Devmurari
Browse files

Implement new Layout manager APIs

DD: go/pk_layout_selection

Test: atest FrameworksServicesTests:KeyboardLayoutManagerTests
Bug: 259530132
Change-Id: Ie7438d33a6eb8e95d3d8c5e5c55f9e7b1be7dcf4
parent 17055397
Loading
Loading
Loading
Loading
+65 −20
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.os.Parcelable;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * Describes a keyboard layout.
@@ -30,6 +31,37 @@ import java.util.Map;
 * @hide
 */
public final class KeyboardLayout implements Parcelable, Comparable<KeyboardLayout> {

    /** Undefined keyboard layout */
    public static final String LAYOUT_TYPE_UNDEFINED = "undefined";

    /** Qwerty-based keyboard layout */
    public static final String LAYOUT_TYPE_QWERTY = "qwerty";

    /** Qwertz-based keyboard layout */
    public static final String LAYOUT_TYPE_QWERTZ = "qwertz";

    /** Azerty-based keyboard layout */
    public static final String LAYOUT_TYPE_AZERTY = "azerty";

    /** Dvorak keyboard layout */
    public static final String LAYOUT_TYPE_DVORAK = "dvorak";

    /** Colemak keyboard layout */
    public static final String LAYOUT_TYPE_COLEMAK = "colemak";

    /** Workman keyboard layout */
    public static final String LAYOUT_TYPE_WORKMAN = "workman";

    /** Turkish-F keyboard layout */
    public static final String LAYOUT_TYPE_TURKISH_F = "turkish_f";

    /** Turkish-Q keyboard layout */
    public static final String LAYOUT_TYPE_TURKISH_Q = "turkish_q";

    /** Keyboard layout that has been enhanced with a large number of extra characters */
    public static final String LAYOUT_TYPE_EXTENDED = "extended";

    private final String mDescriptor;
    private final String mLabel;
    private final String mCollection;
@@ -42,31 +74,24 @@ public final class KeyboardLayout implements Parcelable, Comparable<KeyboardLayo

    /** Currently supported Layout types in the KCM files */
    private enum LayoutType {
        UNDEFINED(0, "undefined"),
        QWERTY(1, "qwerty"),
        QWERTZ(2, "qwertz"),
        AZERTY(3, "azerty"),
        DVORAK(4, "dvorak"),
        COLEMAK(5, "colemak"),
        WORKMAN(6, "workman"),
        TURKISH_F(7, "turkish_f"),
        TURKISH_Q(8, "turkish_q"),
        EXTENDED(9, "extended");
        UNDEFINED(0, LAYOUT_TYPE_UNDEFINED),
        QWERTY(1, LAYOUT_TYPE_QWERTY),
        QWERTZ(2, LAYOUT_TYPE_QWERTZ),
        AZERTY(3, LAYOUT_TYPE_AZERTY),
        DVORAK(4, LAYOUT_TYPE_DVORAK),
        COLEMAK(5, LAYOUT_TYPE_COLEMAK),
        WORKMAN(6, LAYOUT_TYPE_WORKMAN),
        TURKISH_F(7, LAYOUT_TYPE_TURKISH_F),
        TURKISH_Q(8, LAYOUT_TYPE_TURKISH_Q),
        EXTENDED(9, LAYOUT_TYPE_EXTENDED);

        private final int mValue;
        private final String mName;
        private static final Map<Integer, LayoutType> VALUE_TO_ENUM_MAP = new HashMap<>();
        static {
            VALUE_TO_ENUM_MAP.put(UNDEFINED.mValue, UNDEFINED);
            VALUE_TO_ENUM_MAP.put(QWERTY.mValue, QWERTY);
            VALUE_TO_ENUM_MAP.put(QWERTZ.mValue, QWERTZ);
            VALUE_TO_ENUM_MAP.put(AZERTY.mValue, AZERTY);
            VALUE_TO_ENUM_MAP.put(DVORAK.mValue, DVORAK);
            VALUE_TO_ENUM_MAP.put(COLEMAK.mValue, COLEMAK);
            VALUE_TO_ENUM_MAP.put(WORKMAN.mValue, WORKMAN);
            VALUE_TO_ENUM_MAP.put(TURKISH_F.mValue, TURKISH_F);
            VALUE_TO_ENUM_MAP.put(TURKISH_Q.mValue, TURKISH_Q);
            VALUE_TO_ENUM_MAP.put(EXTENDED.mValue, EXTENDED);
            for (LayoutType type : LayoutType.values()) {
                VALUE_TO_ENUM_MAP.put(type.mValue, type);
            }
        }

        private static LayoutType of(int value) {
@@ -206,6 +231,9 @@ public final class KeyboardLayout implements Parcelable, Comparable<KeyboardLayo
        // Note that these arguments are intentionally flipped since you want higher priority
        // keyboards to be listed before lower priority keyboards.
        int result = Integer.compare(another.mPriority, mPriority);
        if (result == 0) {
            result = Integer.compare(mLayoutType.mValue, another.mLayoutType.mValue);
        }
        if (result == 0) {
            result = mLabel.compareToIgnoreCase(another.mLabel);
        }
@@ -226,4 +254,21 @@ public final class KeyboardLayout implements Parcelable, Comparable<KeyboardLayo
                + ", vendorId: " + mVendorId
                + ", productId: " + mProductId;
    }

    /**
     * Check if the provided layout type is supported/valid.
     *
     * @param layoutName name of layout type
     * @return {@code true} if the provided layout type is supported/valid.
     */
    public static boolean isLayoutTypeValid(@NonNull String layoutName) {
        Objects.requireNonNull(layoutName, "Provided layout name should not be null");
        for (LayoutType layoutType : LayoutType.values()) {
            if (layoutName.equals(layoutType.getName())) {
                return true;
            }
        }
        // Layout doesn't match any supported layout types
        return false;
    }
}
+1 −4
Original line number Diff line number Diff line
@@ -3346,10 +3346,7 @@ public class InputManagerService extends IInputManager.Stub
        public void onInputMethodSubtypeChangedForKeyboardLayoutMapping(@UserIdInt int userId,
                @Nullable InputMethodSubtypeHandle subtypeHandle,
                @Nullable InputMethodSubtype subtype) {
            if (DEBUG) {
                Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
                        + " subtypeHandle=" + subtypeHandle);
            }
            mKeyboardLayoutManager.onInputMethodSubtypeChanged(userId, subtypeHandle, subtype);
        }

        @Override
+433 −42

File changed.

Preview size limit exceeded, changes collapsed.

+61 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.input;

import android.annotation.Nullable;
import android.hardware.input.TouchCalibration;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -42,6 +43,7 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.OptionalInt;
@@ -121,6 +123,7 @@ final class PersistentDataStore {
        return false;
    }

    @Nullable
    public String getCurrentKeyboardLayout(String inputDeviceDescriptor) {
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor);
        return state != null ? state.getCurrentKeyboardLayout() : null;
@@ -136,6 +139,22 @@ final class PersistentDataStore {
        return false;
    }

    @Nullable
    public String getKeyboardLayout(String inputDeviceDescriptor, String key) {
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor);
        return state != null ? state.getKeyboardLayout(key) : null;
    }

    public boolean setKeyboardLayout(String inputDeviceDescriptor, String key,
            String keyboardLayoutDescriptor) {
        InputDeviceState state = getOrCreateInputDeviceState(inputDeviceDescriptor);
        if (state.setKeyboardLayout(key, keyboardLayoutDescriptor)) {
            setDirty();
            return true;
        }
        return false;
    }

    public String[] getKeyboardLayouts(String inputDeviceDescriptor) {
        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor);
        if (state == null) {
@@ -387,6 +406,8 @@ final class PersistentDataStore {
        private final ArrayList<String> mKeyboardLayouts = new ArrayList<String>();
        private final SparseIntArray mKeyboardBacklightBrightnessMap = new SparseIntArray();

        private final Map<String, String> mKeyboardLayoutMap = new ArrayMap<>();

        public TouchCalibration getTouchCalibration(int surfaceRotation) {
            try {
                return mTouchCalibration[surfaceRotation];
@@ -409,6 +430,15 @@ final class PersistentDataStore {
            }
        }

        @Nullable
        public String getKeyboardLayout(String key) {
            return mKeyboardLayoutMap.get(key);
        }

        public boolean setKeyboardLayout(String key, String keyboardLayout) {
            return !Objects.equals(mKeyboardLayoutMap.put(key, keyboardLayout), keyboardLayout);
        }

        @Nullable
        public String getCurrentKeyboardLayout() {
            return mCurrentKeyboardLayout;
@@ -507,6 +537,18 @@ final class PersistentDataStore {
                    changed = true;
                }
            }
            List<String> removedEntries = new ArrayList<>();
            for (String key : mKeyboardLayoutMap.keySet()) {
                if (!availableKeyboardLayouts.contains(mKeyboardLayoutMap.get(key))) {
                    removedEntries.add(key);
                }
            }
            if (!removedEntries.isEmpty()) {
                for (String key : removedEntries) {
                    mKeyboardLayoutMap.remove(key);
                }
                changed = true;
            }
            return changed;
        }

@@ -534,6 +576,18 @@ final class PersistentDataStore {
                        }
                        mCurrentKeyboardLayout = descriptor;
                    }
                } else if (parser.getName().equals("keyed-keyboard-layout")) {
                    String key = parser.getAttributeValue(null, "key");
                    if (key == null) {
                        throw new XmlPullParserException(
                                "Missing key attribute on keyed-keyboard-layout.");
                    }
                    String layout = parser.getAttributeValue(null, "layout");
                    if (layout == null) {
                        throw new XmlPullParserException(
                                "Missing layout attribute on keyed-keyboard-layout.");
                    }
                    mKeyboardLayoutMap.put(key, layout);
                } else if (parser.getName().equals("light-info")) {
                    int lightId = parser.getAttributeInt(null, "light-id");
                    int lightBrightness = parser.getAttributeInt(null, "light-brightness");
@@ -607,6 +661,13 @@ final class PersistentDataStore {
                serializer.endTag(null, "keyboard-layout");
            }

            for (String key : mKeyboardLayoutMap.keySet()) {
                serializer.startTag(null, "keyed-keyboard-layout");
                serializer.attribute(null, "key", key);
                serializer.attribute(null, "layout", mKeyboardLayoutMap.get(key));
                serializer.endTag(null, "keyed-keyboard-layout");
            }

            for (int i = 0; i < mKeyboardBacklightBrightnessMap.size(); i++) {
                serializer.startTag(null, "light-info");
                serializer.attributeInt(null, "light-id", mKeyboardBacklightBrightnessMap.keyAt(i));
+311 −0
Original line number Diff line number Diff line
# Copyright (C) 2023 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.

#
# English (US) keyboard layout.
# Unlike the default (generic) keyboard layout, English (US) does not contain any
# special ALT characters.
#

type OVERLAY

### ROW 1

key GRAVE {
    label:                              '`'
    base:                               '`'
    shift:                              '~'
}

key 1 {
    label:                              '1'
    base:                               '1'
    shift:                              '!'
}

key 2 {
    label:                              '2'
    base:                               '2'
    shift:                              '@'
}

key 3 {
    label:                              '3'
    base:                               '3'
    shift:                              '#'
}

key 4 {
    label:                              '4'
    base:                               '4'
    shift:                              '$'
}

key 5 {
    label:                              '5'
    base:                               '5'
    shift:                              '%'
}

key 6 {
    label:                              '6'
    base:                               '6'
    shift:                              '^'
}

key 7 {
    label:                              '7'
    base:                               '7'
    shift:                              '&'
}

key 8 {
    label:                              '8'
    base:                               '8'
    shift:                              '*'
}

key 9 {
    label:                              '9'
    base:                               '9'
    shift:                              '('
}

key 0 {
    label:                              '0'
    base:                               '0'
    shift:                              ')'
}

key MINUS {
    label:                              '-'
    base:                               '-'
    shift:                              '_'
}

key EQUALS {
    label:                              '='
    base:                               '='
    shift:                              '+'
}

### ROW 2

key Q {
    label:                              'Q'
    base:                               'q'
    shift, capslock:                    'Q'
}

key W {
    label:                              'W'
    base:                               'w'
    shift, capslock:                    'W'
}

key E {
    label:                              'E'
    base:                               'e'
    shift, capslock:                    'E'
}

key R {
    label:                              'R'
    base:                               'r'
    shift, capslock:                    'R'
}

key T {
    label:                              'T'
    base:                               't'
    shift, capslock:                    'T'
}

key Y {
    label:                              'Y'
    base:                               'y'
    shift, capslock:                    'Y'
}

key U {
    label:                              'U'
    base:                               'u'
    shift, capslock:                    'U'
}

key I {
    label:                              'I'
    base:                               'i'
    shift, capslock:                    'I'
}

key O {
    label:                              'O'
    base:                               'o'
    shift, capslock:                    'O'
}

key P {
    label:                              'P'
    base:                               'p'
    shift, capslock:                    'P'
}

key LEFT_BRACKET {
    label:                              '['
    base:                               '['
    shift:                              '{'
}

key RIGHT_BRACKET {
    label:                              ']'
    base:                               ']'
    shift:                              '}'
}

key BACKSLASH {
    label:                              '\\'
    base:                               '\\'
    shift:                              '|'
}

### ROW 3

key A {
    label:                              'A'
    base:                               'a'
    shift, capslock:                    'A'
}

key S {
    label:                              'S'
    base:                               's'
    shift, capslock:                    'S'
}

key D {
    label:                              'D'
    base:                               'd'
    shift, capslock:                    'D'
}

key F {
    label:                              'F'
    base:                               'f'
    shift, capslock:                    'F'
}

key G {
    label:                              'G'
    base:                               'g'
    shift, capslock:                    'G'
}

key H {
    label:                              'H'
    base:                               'h'
    shift, capslock:                    'H'
}

key J {
    label:                              'J'
    base:                               'j'
    shift, capslock:                    'J'
}

key K {
    label:                              'K'
    base:                               'k'
    shift, capslock:                    'K'
}

key L {
    label:                              'L'
    base:                               'l'
    shift, capslock:                    'L'
}

key SEMICOLON {
    label:                              ';'
    base:                               ';'
    shift:                              ':'
}

key APOSTROPHE {
    label:                              '\''
    base:                               '\''
    shift:                              '"'
}

### ROW 4

key Z {
    label:                              'Z'
    base:                               'z'
    shift, capslock:                    'Z'
}

key X {
    label:                              'X'
    base:                               'x'
    shift, capslock:                    'X'
}

key C {
    label:                              'C'
    base:                               'c'
    shift, capslock:                    'C'
}

key V {
    label:                              'V'
    base:                               'v'
    shift, capslock:                    'V'
}

key B {
    label:                              'B'
    base:                               'b'
    shift, capslock:                    'B'
}

key N {
    label:                              'N'
    base:                               'n'
    shift, capslock:                    'N'
}

key M {
    label:                              'M'
    base:                               'm'
    shift, capslock:                    'M'
}

key COMMA {
    label:                              ','
    base:                               ','
    shift:                              '<'
}

key PERIOD {
    label:                              '.'
    base:                               '.'
    shift:                              '>'
}

key SLASH {
    label:                              '/'
    base:                               '/'
    shift:                              '?'
}
Loading