1b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer/*
2b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer * Copyright (C) 2016 The Android Open Source Project
3b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer *
4b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer * Licensed under the Apache License, Version 2.0 (the "License");
5b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer * you may not use this file except in compliance with the License.
6b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer * You may obtain a copy of the License at
7b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer *
8b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer *      http://www.apache.org/licenses/LICENSE-2.0
9b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer *
10b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer * Unless required by applicable law or agreed to in writing, software
11b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer * distributed under the License is distributed on an "AS IS" BASIS,
12b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer * See the License for the specific language governing permissions and
14b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer * limitations under the License.
15b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer */
16b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerpackage com.android.inputmethod.latin;
17b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
184db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadiimport android.car.Car;
19b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.car.CarNotConnectedException;
204db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadiimport android.car.drivingstate.CarUxRestrictions;
214db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadiimport android.car.drivingstate.CarUxRestrictionsManager;
22b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.content.ComponentName;
23b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.content.ServiceConnection;
24b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.content.res.Configuration;
25b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.content.res.Resources;
26b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.inputmethodservice.InputMethodService;
27b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.inputmethodservice.Keyboard;
28b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.os.Handler;
29b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.os.IBinder;
30b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.os.Message;
31b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.text.TextUtils;
32b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.util.Log;
33b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.view.LayoutInflater;
34b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.view.View;
35b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.view.inputmethod.EditorInfo;
36b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.view.inputmethod.InputConnection;
37b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport android.widget.FrameLayout;
38b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
39b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport com.android.inputmethod.latin.car.KeyboardView;
40b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
41b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport java.lang.ref.WeakReference;
42b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport java.util.Locale;
43b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
44b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerimport javax.annotation.concurrent.GuardedBy;
45b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
46b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer/**
47b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer * IME for car use case. 2 features are added compared to the original IME.
48b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer * <ul>
494db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi * <li> Monitor driving status, and put a lockout screen on top of the current keyboard if
504db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi * keyboard input is not allowed.
514db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi * <li> Add a close keyboard button so that user dismiss the keyboard when "back" button is not
524db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi * present in the system navigation bar.
53b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer * </ul>
54b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer */
55b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyerpublic class CarLatinIME extends InputMethodService {
56b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private static final String TAG = "CarLatinIME";
57b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private static final String DEFAULT_LANGUAGE = "en";
58b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private static final String LAYOUT_XML = "input_keyboard_layout";
59b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private static final String SYMBOL_LAYOUT_XML = "input_keyboard_layout_symbol";
60b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
6160ee7843f916e9860d14a627734367ef6983566brleix    private static final int KEYCODE_ENTER = '\n';
6260ee7843f916e9860d14a627734367ef6983566brleix    private static final int IME_ACTION_CUSTOM_LABEL = EditorInfo.IME_MASK_ACTION + 1;
63b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private static final int MSG_ENABLE_KEYBOARD = 0;
64b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private static final int KEYCODE_CYCLE_CHAR = -7;
65b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private static final int KEYCODE_MAIN_KEYBOARD = -8;
66b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private static final int KEYCODE_NUM_KEYBOARD = -9;
67b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private static final int KEYCODE_ALPHA_KEYBOARD = -10;
68b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private static final int KEYCODE_CLOSE_KEYBOARD = -99;
69b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
70b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private Keyboard mQweKeyboard;
71b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private Keyboard mSymbolKeyboard;
72b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private Car mCar;
734db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi    private CarUxRestrictionsManager mUxRManager;
74b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
75b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private View mLockoutView;
76b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private KeyboardView mPopupKeyboardView;
77b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
78b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    @GuardedBy("this")
79b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private boolean mKeyboardEnabled = true;
80b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private KeyboardView mKeyboardView;
81b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private Locale mLocale;
82b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private final Handler mHandler;
83b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
84b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private FrameLayout mKeyboardWrapper;
85b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private EditorInfo mEditorInfo;
86b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
87b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private static final class HideKeyboardHandler extends Handler {
88b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        private final WeakReference<CarLatinIME> mIME;
894db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi
90b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        public HideKeyboardHandler(CarLatinIME ime) {
91b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            mIME = new WeakReference<CarLatinIME>(ime);
92b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        }
934db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi
94b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        @Override
95b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        public void handleMessage(Message msg) {
96b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            switch (msg.what) {
97b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                case MSG_ENABLE_KEYBOARD:
98b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    if (mIME.get() != null) {
99b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                        mIME.get().updateKeyboardState(msg.arg1 == 1);
100b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    }
101b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    break;
102b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            }
103b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        }
104b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    }
105b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
106b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private final ServiceConnection mCarConnectionListener =
107b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            new ServiceConnection() {
108b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void onServiceConnected(ComponentName name, IBinder service) {
109b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    Log.d(TAG, "Car Service connected");
110b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    try {
1114db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                        mUxRManager = (CarUxRestrictionsManager) mCar.getCarManager(
1124db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                Car.CAR_UX_RESTRICTION_SERVICE);
1134db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                        if (mUxRManager != null) {
1144db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                            mUxRManager.registerListener(mCarUxRListener);
1154db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                        } else {
1164db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                            Log.e(TAG, "CarUxRestrictions service not available");
1174db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                        }
118b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    } catch (CarNotConnectedException e) {
119b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                        Log.e(TAG, "car not connected", e);
120b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    }
121b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
122b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
123b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
124b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void onServiceDisconnected(ComponentName name) {
125b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    Log.e(TAG, "CarService: onServiceDisconnedted " + name);
126b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
127b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            };
128b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
1298c19f863a25c4549d7729baaeaef8dd656a96cf3Ram Periathiruvadi    private final CarUxRestrictionsManager.OnUxRestrictionsChangedListener mCarUxRListener =
1308c19f863a25c4549d7729baaeaef8dd656a96cf3Ram Periathiruvadi            new CarUxRestrictionsManager.OnUxRestrictionsChangedListener() {
131b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
1324db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                public void onUxRestrictionsChanged(CarUxRestrictions restrictions) {
1334db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                    if (restrictions == null) {
134b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                        return;
135b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    }
136b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    boolean keyboardEnabled =
1374db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                            (restrictions.getActiveRestrictions()
1384db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                    & CarUxRestrictions.UX_RESTRICTIONS_NO_KEYBOARD) == 0;
139b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    mHandler.sendMessage(mHandler.obtainMessage(
140b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            MSG_ENABLE_KEYBOARD, keyboardEnabled ? 1 : 0, 0, null));
141b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
142b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            };
143b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
144b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    public CarLatinIME() {
145b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        super();
146b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mHandler = new HideKeyboardHandler(this);
147b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    }
148b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
149b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    @Override
150b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    public void onCreate() {
151b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        super.onCreate();
152b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mCar = Car.createCar(this, mCarConnectionListener);
153b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mCar.connect();
154b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
155b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mQweKeyboard = createKeyboard(LAYOUT_XML);
156b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mSymbolKeyboard = createKeyboard(SYMBOL_LAYOUT_XML);
157b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    }
158b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
159b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    @Override
160b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    public void onDestroy() {
161b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        super.onDestroy();
162b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        if (mCar != null) {
163b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            mCar.disconnect();
164b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        }
165b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    }
166b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
167b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    @Override
168b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    public View onCreateInputView() {
169b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        if (Log.isLoggable(TAG, Log.DEBUG)) {
170b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            Log.d(TAG, "onCreateInputView");
171b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        }
172b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        super.onCreateInputView();
173b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
174b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        View v = LayoutInflater.from(this).inflate(R.layout.input_keyboard, null);
175b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mKeyboardView = (KeyboardView) v.findViewById(R.id.keyboard);
176b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
177b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mLockoutView = v.findViewById(R.id.lockout);
178b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mPopupKeyboardView = (KeyboardView) v.findViewById(R.id.popup_keyboard);
179b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mKeyboardView.setPopupKeyboardView(mPopupKeyboardView);
180b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mKeyboardWrapper = (FrameLayout) v.findViewById(R.id.keyboard_wrapper);
181b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mLockoutView.setBackgroundResource(R.color.ime_background_letters);
182b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
183b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        synchronized (this) {
184b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            updateKeyboardStateLocked();
185b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        }
186b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        return v;
187b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    }
188b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
189b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
190b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    @Override
191b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    public void onStartInputView(EditorInfo editorInfo, boolean reastarting) {
192b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        super.onStartInputView(editorInfo, reastarting);
193b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mEditorInfo = editorInfo;
194b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mKeyboardView.setKeyboard(mQweKeyboard, getLocale());
195b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mKeyboardWrapper.setPadding(0,
196b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                getResources().getDimensionPixelSize(R.dimen.keyboard_padding_vertical), 0, 0);
197b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mKeyboardView.setOnKeyboardActionListener(mKeyboardActionListener);
198b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mPopupKeyboardView.setOnKeyboardActionListener(mPopupKeyboardActionListener);
199b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mKeyboardView.setShifted(mKeyboardView.isShifted());
200b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        updateCapitalization();
201b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    }
202b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
203b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    public Locale getLocale() {
204b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        if (mLocale == null) {
205b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            mLocale = this.getResources().getConfiguration().locale;
206b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        }
207b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        return mLocale;
208b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    }
209b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
210b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    @Override
211b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    public boolean onEvaluateFullscreenMode() {
212b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        return false;
213b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    }
214b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
215b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private Keyboard createKeyboard(String layoutXml) {
216b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        Resources res = this.getResources();
217b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        Configuration configuration = res.getConfiguration();
218b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        Locale oldLocale = configuration.locale;
219b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        configuration.locale = new Locale(DEFAULT_LANGUAGE);
220b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        res.updateConfiguration(configuration, res.getDisplayMetrics());
221b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        Keyboard ret = new Keyboard(
222b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                this, res.getIdentifier(layoutXml, "xml", getPackageName()));
223b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mLocale = configuration.locale;
224b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        configuration.locale = oldLocale;
225b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        return ret;
226b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    }
227b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
228b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    public void updateKeyboardState(boolean enabled) {
229b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        synchronized (this) {
230b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            mKeyboardEnabled = enabled;
231b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            updateKeyboardStateLocked();
232b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        }
233b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    }
234b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
235b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private void updateKeyboardStateLocked() {
236b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        if (mLockoutView == null) {
237b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            return;
238b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        }
239b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mLockoutView.setVisibility(mKeyboardEnabled ? View.GONE : View.VISIBLE);
240b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    }
241b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
242b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private void toggleCapitalization() {
243b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mKeyboardView.setShifted(!mKeyboardView.isShifted());
244b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    }
245b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
246b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private void updateCapitalization() {
247b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        boolean shouldCapitalize =
248b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                getCurrentInputConnection().getCursorCapsMode(mEditorInfo.inputType) != 0;
249b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        mKeyboardView.setShifted(shouldCapitalize);
250b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    }
251b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
252b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private final KeyboardView.OnKeyboardActionListener mKeyboardActionListener =
253b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            new KeyboardView.OnKeyboardActionListener() {
254b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
255b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void onPress(int primaryCode) {
256b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
257b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
258b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
259b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void onRelease(int primaryCode) {
260b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
261b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
262b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
263b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void onKey(int primaryCode, int[] keyCodes) {
264b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    if (Log.isLoggable(TAG, Log.DEBUG)) {
2654db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                        Log.d(TAG, "onKey " + primaryCode);
266b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    }
267b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    InputConnection inputConnection = getCurrentInputConnection();
268b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    switch (primaryCode) {
269b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                        case Keyboard.KEYCODE_SHIFT:
270b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            toggleCapitalization();
271b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            break;
272b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                        case Keyboard.KEYCODE_MODE_CHANGE:
273b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            if (mKeyboardView.getKeyboard() == mQweKeyboard) {
274b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                                mKeyboardView.setKeyboard(mSymbolKeyboard, getLocale());
275b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            } else {
276b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                                mKeyboardView.setKeyboard(mQweKeyboard, getLocale());
277b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            }
278b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            break;
279b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                        case Keyboard.KEYCODE_DONE:
280b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            int action = mEditorInfo.imeOptions & EditorInfo.IME_MASK_ACTION;
281b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            inputConnection.performEditorAction(action);
282b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            break;
283b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                        case Keyboard.KEYCODE_DELETE:
284b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            inputConnection.deleteSurroundingText(1, 0);
285b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            updateCapitalization();
286b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            break;
287b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                        case KEYCODE_MAIN_KEYBOARD:
288b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            mKeyboardView.setKeyboard(mQweKeyboard, getLocale());
289b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            break;
290b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                        case KEYCODE_NUM_KEYBOARD:
291b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            // No number keyboard layout support.
292b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            break;
293b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                        case KEYCODE_ALPHA_KEYBOARD:
294b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            //loadKeyboard(ALPHA_LAYOUT_XML);
295b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            break;
296b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                        case KEYCODE_CLOSE_KEYBOARD:
297b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            hideWindow();
298b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            break;
299b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                        case KEYCODE_CYCLE_CHAR:
300b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            CharSequence text = inputConnection.getTextBeforeCursor(1, 0);
301b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            if (TextUtils.isEmpty(text)) {
302b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                                break;
303b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            }
304b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
305b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            char currChar = text.charAt(0);
306b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            char altChar = cycleCharacter(currChar);
307b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            // Don't modify text if there is no alternate.
308b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            if (currChar != altChar) {
309b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                                inputConnection.deleteSurroundingText(1, 0);
310b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                                inputConnection.commitText(String.valueOf(altChar), 1);
311b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            }
312b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            break;
31360ee7843f916e9860d14a627734367ef6983566brleix                        case KEYCODE_ENTER:
3144db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                            final int imeOptionsActionId = getImeOptionsActionIdFromEditorInfo(
3154db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                    mEditorInfo);
31660ee7843f916e9860d14a627734367ef6983566brleix                            if (IME_ACTION_CUSTOM_LABEL == imeOptionsActionId) {
3174db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // Either we have an actionLabel and we should
3184db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // performEditorAction with
31960ee7843f916e9860d14a627734367ef6983566brleix                                // actionId regardless of its value.
32060ee7843f916e9860d14a627734367ef6983566brleix                                inputConnection.performEditorAction(mEditorInfo.actionId);
32160ee7843f916e9860d14a627734367ef6983566brleix                            } else if (EditorInfo.IME_ACTION_NONE != imeOptionsActionId) {
3224db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // We didn't have an actionLabel, but we had another action to
3234db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // execute.
3244db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // EditorInfo.IME_ACTION_NONE explicitly means no action. In
3254db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // contrast,
3264db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // EditorInfo.IME_ACTION_UNSPECIFIED is the default value for an
3274db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // action, so it
3284db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // means there should be an action and the app didn't bother to
3294db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // set a specific
3304db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // code for it - presumably it only handles one. It does not have
3314db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // to be treated
3324db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // in any specific way: anything that is not IME_ACTION_NONE
3334db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // should be sent to
33460ee7843f916e9860d14a627734367ef6983566brleix                                // performEditorAction.
33560ee7843f916e9860d14a627734367ef6983566brleix                                inputConnection.performEditorAction(imeOptionsActionId);
33660ee7843f916e9860d14a627734367ef6983566brleix                            } else {
3374db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // No action label, and the action from imeOptions is NONE: this
3384db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                // is a regular
33960ee7843f916e9860d14a627734367ef6983566brleix                                // enter key that should input a carriage return.
34060ee7843f916e9860d14a627734367ef6983566brleix                                String txt = Character.toString((char) primaryCode);
34160ee7843f916e9860d14a627734367ef6983566brleix                                if (mKeyboardView.isShifted()) {
34260ee7843f916e9860d14a627734367ef6983566brleix                                    txt = txt.toUpperCase(mLocale);
34360ee7843f916e9860d14a627734367ef6983566brleix                                }
34460ee7843f916e9860d14a627734367ef6983566brleix                                if (Log.isLoggable(TAG, Log.DEBUG)) {
34560ee7843f916e9860d14a627734367ef6983566brleix                                    Log.d(TAG, "commitText " + txt);
34660ee7843f916e9860d14a627734367ef6983566brleix                                }
34760ee7843f916e9860d14a627734367ef6983566brleix                                inputConnection.commitText(txt, 1);
34860ee7843f916e9860d14a627734367ef6983566brleix                                updateCapitalization();
34960ee7843f916e9860d14a627734367ef6983566brleix                            }
35060ee7843f916e9860d14a627734367ef6983566brleix                            break;
351b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                        default:
352b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            String commitText = Character.toString((char) primaryCode);
353b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            // Chars always come through as lowercase, so we have to explicitly
354b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            // uppercase them if the keyboard is shifted.
355b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            if (mKeyboardView.isShifted()) {
356b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                                commitText = commitText.toUpperCase(mLocale);
357b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            }
358b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            if (Log.isLoggable(TAG, Log.DEBUG)) {
3594db4661c51d6c6a260faf6fb44367676a4c6d4e5Ram Periathiruvadi                                Log.d(TAG, "commitText " + commitText);
360b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            }
361b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            inputConnection.commitText(commitText, 1);
362b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                            updateCapitalization();
363b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    }
364b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
365b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
366b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
367b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void onText(CharSequence text) {
368b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
369b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
370b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
371b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void swipeLeft() {
372b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
373b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
374b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
375b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void swipeRight() {
376b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
377b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
378b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
379b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void swipeDown() {
380b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
381b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
382b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
383b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void swipeUp() {
384b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
385b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
386b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
387b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void stopInput() {
388b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    hideWindow();
389b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
390b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            };
391b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
392b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private final KeyboardView.OnKeyboardActionListener mPopupKeyboardActionListener =
393b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            new KeyboardView.OnKeyboardActionListener() {
394b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
395b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void onPress(int primaryCode) {
396b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
397b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
398b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
399b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void onRelease(int primaryCode) {
400b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
401b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
402b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
403b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void onKey(int primaryCode, int[] keyCodes) {
404b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    InputConnection inputConnection = getCurrentInputConnection();
405b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    String commitText = Character.toString((char) primaryCode);
406b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    // Chars always come through as lowercase, so we have to explicitly
407b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    // uppercase them if the keyboard is shifted.
408b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    if (mKeyboardView.isShifted()) {
409b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                        commitText = commitText.toUpperCase(mLocale);
410b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    }
411b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    inputConnection.commitText(commitText, 1);
412b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    updateCapitalization();
413b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    mKeyboardView.dismissPopupKeyboard();
414b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
415b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
416b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
417b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void onText(CharSequence text) {
418b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
419b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
420b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
421b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void swipeLeft() {
422b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
423b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
424b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
425b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void swipeRight() {
426b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
427b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
428b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
429b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void swipeDown() {
430b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
431b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
432b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
433b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void swipeUp() {
434b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
435b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
436b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                @Override
437b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                public void stopInput() {
438b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                    hideWindow();
439b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer                }
440b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            };
441b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer
442b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    /**
443b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer     * Cycle through alternate characters of the given character. Return the same character if
444b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer     * there is no alternate.
445b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer     */
446b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    private char cycleCharacter(char current) {
447b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        if (Character.isUpperCase(current)) {
448b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            return String.valueOf(current).toLowerCase(mLocale).charAt(0);
449b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        } else {
450b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer            return String.valueOf(current).toUpperCase(mLocale).charAt(0);
451b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer        }
452b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer    }
45360ee7843f916e9860d14a627734367ef6983566brleix
45460ee7843f916e9860d14a627734367ef6983566brleix    private int getImeOptionsActionIdFromEditorInfo(final EditorInfo editorInfo) {
45560ee7843f916e9860d14a627734367ef6983566brleix        if ((editorInfo.imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) {
45660ee7843f916e9860d14a627734367ef6983566brleix            return EditorInfo.IME_ACTION_NONE;
45760ee7843f916e9860d14a627734367ef6983566brleix        } else if (editorInfo.actionLabel != null) {
45860ee7843f916e9860d14a627734367ef6983566brleix            return IME_ACTION_CUSTOM_LABEL;
45960ee7843f916e9860d14a627734367ef6983566brleix        } else {
46060ee7843f916e9860d14a627734367ef6983566brleix            // Note: this is different from editorInfo.actionId, hence "ImeOptionsActionId"
46160ee7843f916e9860d14a627734367ef6983566brleix            return editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION;
46260ee7843f916e9860d14a627734367ef6983566brleix        }
46360ee7843f916e9860d14a627734367ef6983566brleix    }
464b8d05222f6f88e9c6ab64f88e9b9eba194a5c221Rakesh Iyer}
465