1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.autofillkeyboard; 18 19 import android.util.SparseArray; 20 import android.view.LayoutInflater; 21 import android.view.View; 22 import android.widget.TextView; 23 24 /** Controls the visible virtual keyboard view. */ 25 final class Keyboard { 26 27 private static final int NUM_STATES = 4; 28 private static final int STATE_SHIFT = 1; 29 private static final int STATE_SYMBOL = 2; 30 31 private final AutofillImeService mAutofillImeService; 32 private final int mViewResId; 33 private final SparseArray<String> mKeyMapping; 34 private View mKeyboardView; 35 private int mState; 36 Keyboard(AutofillImeService autofillImeService, int viewResId, SparseArray<String> keyMapping)37 private Keyboard(AutofillImeService autofillImeService, int viewResId, 38 SparseArray<String> keyMapping) { 39 this.mAutofillImeService = autofillImeService; 40 this.mViewResId = viewResId; 41 this.mKeyMapping = keyMapping; 42 this.mState = 0; 43 } 44 getLabel(String data)45 private static String getLabel(String data) { 46 if ("SHI".equals(data)) { 47 return "↑"; 48 } else if ("DEL".equals(data)) { 49 return "←"; 50 } else if ("SYM".equals(data)) { 51 return "?123"; 52 } else if ("SPA".equals(data)) { 53 return "[ ]"; 54 } else if ("ENT".equals(data)) { 55 return "↩"; 56 } else { 57 return data; 58 } 59 } 60 qwerty(AutofillImeService autofillImeService)61 static Keyboard qwerty(AutofillImeService autofillImeService) { 62 SparseArray<String> keyMapping = new SparseArray<>(); 63 keyMapping.put(R.id.key_pos_0_0, "qQ1\u007E"); 64 keyMapping.put(R.id.key_pos_0_1, "wW2\u0060"); 65 keyMapping.put(R.id.key_pos_0_2, "eE3\u007C"); 66 keyMapping.put(R.id.key_pos_0_3, "rR4\u2022"); 67 keyMapping.put(R.id.key_pos_0_4, "tT5\u221A"); 68 keyMapping.put(R.id.key_pos_0_5, "yY6\u03C0"); 69 keyMapping.put(R.id.key_pos_0_6, "uU7\u00F7"); 70 keyMapping.put(R.id.key_pos_0_7, "iI8\u00D7"); 71 keyMapping.put(R.id.key_pos_0_8, "oO9\u00B6"); 72 keyMapping.put(R.id.key_pos_0_9, "pP0\u2206"); 73 keyMapping.put(R.id.key_pos_1_0, "aA@\u00A3"); 74 keyMapping.put(R.id.key_pos_1_1, "sS#\u00A2"); 75 keyMapping.put(R.id.key_pos_1_2, "dD$\u20AC"); 76 keyMapping.put(R.id.key_pos_1_3, "fF_\u00A5"); 77 keyMapping.put(R.id.key_pos_1_4, "gG&\u005E"); 78 keyMapping.put(R.id.key_pos_1_5, "hH-="); 79 keyMapping.put(R.id.key_pos_1_6, "jJ+{"); 80 keyMapping.put(R.id.key_pos_1_7, "kK(}"); 81 keyMapping.put(R.id.key_pos_1_8, "lL)\\"); 82 keyMapping.put(R.id.key_pos_2_0, "zZ*%"); 83 keyMapping.put(R.id.key_pos_2_1, "xX\"\u00A9"); 84 keyMapping.put(R.id.key_pos_2_2, "cC'\u00AE"); 85 keyMapping.put(R.id.key_pos_2_3, "vV:\u2122"); 86 keyMapping.put(R.id.key_pos_2_4, "bB;\u2713"); 87 keyMapping.put(R.id.key_pos_2_5, "nN!["); 88 keyMapping.put(R.id.key_pos_2_6, "mM?]"); 89 keyMapping.put(R.id.key_pos_bottom_0, ",,,<"); 90 keyMapping.put(R.id.key_pos_bottom_1, "...>"); 91 keyMapping.put(R.id.key_pos_shift, "SHI"); 92 keyMapping.put(R.id.key_pos_del, "DEL"); 93 keyMapping.put(R.id.key_pos_symbol, "SYM"); 94 keyMapping.put(R.id.key_pos_space, "SPA"); 95 keyMapping.put(R.id.key_pos_enter, "ENT"); 96 return new Keyboard(autofillImeService, R.layout.keyboard_10_9_9, keyMapping); 97 } 98 inflateKeyboardView(LayoutInflater inflater, InputView inputView)99 View inflateKeyboardView(LayoutInflater inflater, InputView inputView) { 100 mKeyboardView = inflater.inflate(mViewResId, inputView, false); 101 mapKeys(); 102 return mKeyboardView; 103 } 104 reset()105 void reset() { 106 mState = 0; 107 mapKeys(); 108 } 109 mapKeys()110 private void mapKeys() { 111 for (int i = 0; i < mKeyMapping.size(); i++) { 112 TextView softkey = mKeyboardView.findViewById(mKeyMapping.keyAt(i)); 113 String rawData = mKeyMapping.valueAt(i); 114 String data = rawData.length() != NUM_STATES ? rawData : rawData.substring(mState, 115 mState + 1); 116 softkey.setText(getLabel(data)); 117 softkey.setOnClickListener(v -> handle(data)); 118 } 119 } 120 handle(String data)121 private void handle(String data) { 122 if ("SHI".equals(data)) { 123 // Toggle STATE_SHIFT. 124 mState = mState ^ STATE_SHIFT; 125 mapKeys(); 126 } else if ("SYM".equals(data)) { 127 // Toggle STATE_SYMBOL and clear STATE_SHIFT. 128 mState = (mState ^ STATE_SYMBOL) & ~STATE_SHIFT; 129 mapKeys(); 130 } else { 131 mAutofillImeService.handle(data); 132 } 133 } 134 } 135