/* * Copyright (C) 2019 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.example.android.autofillkeyboard; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; /** Controls the visible virtual keyboard view. */ final class Keyboard { private static final int NUM_STATES = 4; private static final int STATE_SHIFT = 1; private static final int STATE_SYMBOL = 2; private final AutofillImeService mAutofillImeService; private final int mViewResId; private final SparseArray mKeyMapping; private View mKeyboardView; private int mState; private Keyboard(AutofillImeService autofillImeService, int viewResId, SparseArray keyMapping) { this.mAutofillImeService = autofillImeService; this.mViewResId = viewResId; this.mKeyMapping = keyMapping; this.mState = 0; } private static String getLabel(String data) { if ("SHI".equals(data)) { return "↑"; } else if ("DEL".equals(data)) { return "←"; } else if ("SYM".equals(data)) { return "?123"; } else if ("SPA".equals(data)) { return "[ ]"; } else if ("ENT".equals(data)) { return "↩"; } else { return data; } } static Keyboard qwerty(AutofillImeService autofillImeService) { SparseArray keyMapping = new SparseArray<>(); keyMapping.put(R.id.key_pos_0_0, "qQ1\u007E"); keyMapping.put(R.id.key_pos_0_1, "wW2\u0060"); keyMapping.put(R.id.key_pos_0_2, "eE3\u007C"); keyMapping.put(R.id.key_pos_0_3, "rR4\u2022"); keyMapping.put(R.id.key_pos_0_4, "tT5\u221A"); keyMapping.put(R.id.key_pos_0_5, "yY6\u03C0"); keyMapping.put(R.id.key_pos_0_6, "uU7\u00F7"); keyMapping.put(R.id.key_pos_0_7, "iI8\u00D7"); keyMapping.put(R.id.key_pos_0_8, "oO9\u00B6"); keyMapping.put(R.id.key_pos_0_9, "pP0\u2206"); keyMapping.put(R.id.key_pos_1_0, "aA@\u00A3"); keyMapping.put(R.id.key_pos_1_1, "sS#\u00A2"); keyMapping.put(R.id.key_pos_1_2, "dD$\u20AC"); keyMapping.put(R.id.key_pos_1_3, "fF_\u00A5"); keyMapping.put(R.id.key_pos_1_4, "gG&\u005E"); keyMapping.put(R.id.key_pos_1_5, "hH-="); keyMapping.put(R.id.key_pos_1_6, "jJ+{"); keyMapping.put(R.id.key_pos_1_7, "kK(}"); keyMapping.put(R.id.key_pos_1_8, "lL)\\"); keyMapping.put(R.id.key_pos_2_0, "zZ*%"); keyMapping.put(R.id.key_pos_2_1, "xX\"\u00A9"); keyMapping.put(R.id.key_pos_2_2, "cC'\u00AE"); keyMapping.put(R.id.key_pos_2_3, "vV:\u2122"); keyMapping.put(R.id.key_pos_2_4, "bB;\u2713"); keyMapping.put(R.id.key_pos_2_5, "nN!["); keyMapping.put(R.id.key_pos_2_6, "mM?]"); keyMapping.put(R.id.key_pos_bottom_0, ",,,<"); keyMapping.put(R.id.key_pos_bottom_1, "...>"); keyMapping.put(R.id.key_pos_shift, "SHI"); keyMapping.put(R.id.key_pos_del, "DEL"); keyMapping.put(R.id.key_pos_symbol, "SYM"); keyMapping.put(R.id.key_pos_space, "SPA"); keyMapping.put(R.id.key_pos_enter, "ENT"); return new Keyboard(autofillImeService, R.layout.keyboard_10_9_9, keyMapping); } View inflateKeyboardView(LayoutInflater inflater, InputView inputView) { mKeyboardView = inflater.inflate(mViewResId, inputView, false); mapKeys(); return mKeyboardView; } void reset() { mState = 0; mapKeys(); } private void mapKeys() { for (int i = 0; i < mKeyMapping.size(); i++) { TextView softkey = mKeyboardView.findViewById(mKeyMapping.keyAt(i)); String rawData = mKeyMapping.valueAt(i); String data = rawData.length() != NUM_STATES ? rawData : rawData.substring(mState, mState + 1); softkey.setText(getLabel(data)); softkey.setOnClickListener(v -> handle(data)); } } private void handle(String data) { if ("SHI".equals(data)) { // Toggle STATE_SHIFT. mState = mState ^ STATE_SHIFT; mapKeys(); } else if ("SYM".equals(data)) { // Toggle STATE_SYMBOL and clear STATE_SHIFT. mState = (mState ^ STATE_SYMBOL) & ~STATE_SHIFT; mapKeys(); } else { mAutofillImeService.handle(data); } } }