1 /*
2  * Copyright (C) 2022 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.android.apps.inputmethod.simpleime;
18 
19 import android.text.TextUtils;
20 import android.util.Log;
21 import android.util.SparseArray;
22 import android.view.KeyEvent;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 import android.view.ViewGroup;
26 import android.widget.TextView;
27 
28 /** Controls the visible virtual keyboard view. */
29 final class SimpleKeyboard {
30     private static final String TAG = "SimpleKeyboard";
31 
32     private static final int[] SOFT_KEY_IDS =
33             new int[] {
34                 R.id.key_pos_0_0,
35                 R.id.key_pos_0_1,
36                 R.id.key_pos_0_2,
37                 R.id.key_pos_0_3,
38                 R.id.key_pos_0_4,
39                 R.id.key_pos_0_5,
40                 R.id.key_pos_0_6,
41                 R.id.key_pos_0_7,
42                 R.id.key_pos_0_8,
43                 R.id.key_pos_0_9,
44                 R.id.key_pos_1_0,
45                 R.id.key_pos_1_1,
46                 R.id.key_pos_1_2,
47                 R.id.key_pos_1_3,
48                 R.id.key_pos_1_4,
49                 R.id.key_pos_1_5,
50                 R.id.key_pos_1_6,
51                 R.id.key_pos_1_7,
52                 R.id.key_pos_1_8,
53                 R.id.key_pos_2_0,
54                 R.id.key_pos_2_1,
55                 R.id.key_pos_2_2,
56                 R.id.key_pos_2_3,
57                 R.id.key_pos_2_4,
58                 R.id.key_pos_2_5,
59                 R.id.key_pos_2_6,
60                 R.id.key_pos_shift,
61                 R.id.key_pos_del,
62                 R.id.key_pos_symbol,
63                 R.id.key_pos_comma,
64                 R.id.key_pos_space,
65                 R.id.key_pos_period,
66                 R.id.key_pos_enter,
67             };
68 
69     private final SimpleInputMethodService mSimpleInputMethodService;
70     private final int mViewResId;
71     private final SparseArray<TextView> mSoftKeyViews = new SparseArray<>();
72     private View mKeyboardView;
73     private int mKeyboardState;
74 
SimpleKeyboard(SimpleInputMethodService simpleInputMethodService, int viewResId)75     SimpleKeyboard(SimpleInputMethodService simpleInputMethodService, int viewResId) {
76         this.mSimpleInputMethodService = simpleInputMethodService;
77         this.mViewResId = viewResId;
78         this.mKeyboardState = 0;
79     }
80 
inflateKeyboardView(LayoutInflater inflater, ViewGroup inputView)81     View inflateKeyboardView(LayoutInflater inflater, ViewGroup inputView) {
82         mKeyboardView = inflater.inflate(mViewResId, inputView, false);
83         mapSoftKeys();
84         return mKeyboardView;
85     }
86 
mapSoftKeys()87     private void mapSoftKeys() {
88         for (int id : SOFT_KEY_IDS) {
89             TextView softKeyView = mKeyboardView.findViewById(id);
90             mSoftKeyViews.put(id, softKeyView);
91             String tagData = softKeyView.getTag() != null ? softKeyView.getTag().toString() : null;
92             softKeyView.setOnClickListener(v -> handle(tagData));
93         }
94     }
95 
handle(String data)96     private void handle(String data) {
97         Log.i(TAG, "handle(): " + data);
98         if (TextUtils.isEmpty(data)) {
99             return;
100         }
101         if ("KEYCODE_SHIFT".equals(data)) {
102             handleShift();
103             return;
104         }
105 
106         mSimpleInputMethodService.handle(data, mKeyboardState);
107     }
108 
handleShift()109     private void handleShift() {
110         mKeyboardState = toggleShiftState(mKeyboardState);
111         Log.v(TAG, "currentKeyboardState: " + mKeyboardState);
112         boolean isShiftOn = isShiftOn(mKeyboardState);
113         for (int i = 0; i < mSoftKeyViews.size(); i++) {
114             TextView softKeyView = mSoftKeyViews.valueAt(i);
115             softKeyView.setAllCaps(isShiftOn);
116         }
117     }
118 
isShiftOn(int state)119     private static boolean isShiftOn(int state) {
120         return (state & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON;
121     }
122 
toggleShiftState(int state)123     private static int toggleShiftState(int state) {
124         return state ^ KeyEvent.META_SHIFT_ON;
125     }
126 }
127