InputMethodManagerService.java revision 7265d9bd6d80c5bedaa6de2b80f6619a301a07c8
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006-2008 The Android Open Source Project
3ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the License at
7ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
9ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * License for the specific language governing permissions and limitations under
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornimport com.android.internal.content.PackageMonitor;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.os.HandlerCaller;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.IInputContext;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.IInputMethod;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.IInputMethodCallback;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.IInputMethodClient;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.IInputMethodManager;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.IInputMethodSession;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.InputBindResult;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
297a0f36bd93ad8a5b8cb3e1fe56dbdb43a0ad3a57Joe Onoratoimport com.android.server.StatusBarManagerService;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParserException;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.ActivityManagerNative;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.AlertDialog;
35dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackbornimport android.app.PendingIntent;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ComponentName;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.DialogInterface;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.DialogInterface.OnCancelListener;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ServiceConnection;
446da35a0c1205398b7df4776e359f7794584fb128Brandon Ballingerimport android.content.pm.ApplicationInfo;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.ResolveInfo;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.ServiceInfo;
48e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasaniimport android.content.res.Configuration;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.ContentObserver;
52857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onoratoimport android.inputmethodservice.InputMethodService;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IInterface;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
604df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Projectimport android.os.ResultReceiver;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
634d733290a112fbe7ca5631ee870094b538f39d80satokimport android.os.SystemProperties;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
65e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasaniimport android.provider.Settings.Secure;
66ab751aa085433e9f735d2e7603459c6c7e9d2fb0satokimport android.provider.Settings.SettingNotFoundException;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.EventLog;
69ab751aa085433e9f735d2e7603459c6c7e9d2fb0satokimport android.util.Pair;
708a9b22056b13477f59df934928c00c58b5871c95Joe Onoratoimport android.util.Slog;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.PrintWriterPrinter;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Printer;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.IWindowManager;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.WindowManager;
75ab751aa085433e9f735d2e7603459c6c7e9d2fb0satokimport android.view.inputmethod.EditorInfo;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.inputmethod.InputBinding;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.inputmethod.InputMethod;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.inputmethod.InputMethodInfo;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.inputmethod.InputMethodManager;
80ab751aa085433e9f735d2e7603459c6c7e9d2fb0satokimport android.view.inputmethod.InputMethodSubtype;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
85913a8925c07e854a80bf5df87561f290d3a56d61satokimport java.text.Collator;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
887f35c8cc88bea5230f001dd4356f864845d202e5satokimport java.util.HashSet;
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List;
90913a8925c07e854a80bf5df87561f290d3a56d61satokimport java.util.Map;
91913a8925c07e854a80bf5df87561f290d3a56d61satokimport java.util.TreeMap;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This class provides a system service that manages input methods.
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class InputMethodManagerService extends IInputMethodManager.Stub
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        implements ServiceConnection, Handler.Callback {
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final boolean DEBUG = false;
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final String TAG = "InputManagerService";
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_SHOW_IM_PICKER = 1;
102ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    static final int MSG_SHOW_IM_SUBTYPE_PICKER = 2;
10347a44916e2fb33cf4751906386d5f5c903b28d8bsatok    static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 3;
104217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok    static final int MSG_SHOW_IM_CONFIG = 4;
105ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_UNBIND_INPUT = 1000;
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_BIND_INPUT = 1010;
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_SHOW_SOFT_INPUT = 1020;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_HIDE_SOFT_INPUT = 1030;
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_ATTACH_TOKEN = 1040;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_CREATE_SESSION = 1050;
112ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_START_INPUT = 2000;
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_RESTART_INPUT = 2010;
115ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_UNBIND_METHOD = 3000;
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_BIND_METHOD = 3010;
118ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final long TIME_TO_RECONNECT = 10*1000;
120ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
121ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private static final int NOT_A_SUBTYPE_ID = -1;
122723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    private static final String NOT_A_SUBTYPE_ID_STR = String.valueOf(NOT_A_SUBTYPE_ID);
1234e4569dab5c75804b01a19b2d6e6101b445c1c68satok    private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
1244e4569dab5c75804b01a19b2d6e6101b445c1c68satok    private static final String SUBTYPE_MODE_VOICE = "voice";
1254e4569dab5c75804b01a19b2d6e6101b445c1c68satok
12657ffc00239edcfe733832771e1429fca20182207satok    // TODO: Will formalize this value as API
12757ffc00239edcfe733832771e1429fca20182207satok    private static final String SUBTYPE_EXTRAVALUE_EXCLUDE_FROM_LAST_IME =
12857ffc00239edcfe733832771e1429fca20182207satok            "excludeFromLastInputMethod";
12957ffc00239edcfe733832771e1429fca20182207satok
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final Context mContext;
1317d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn    final Resources mRes;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final Handler mHandler;
133d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    final InputMethodSettings mSettings;
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final SettingsObserver mSettingsObserver;
135089de88fc2f08d284cf8031aa33cff06011a4162Joe Onorato    final StatusBarManagerService mStatusBar;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final IWindowManager mIWindowManager;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final HandlerCaller mCaller;
138ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final InputBindResult mNoBinding = new InputBindResult(null, null, -1);
140ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // All known input methods.  mMethodMap also serves as the global
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // lock for this class.
143d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    final ArrayList<InputMethodInfo> mMethodList = new ArrayList<InputMethodInfo>();
144d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    final HashMap<String, InputMethodInfo> mMethodMap = new HashMap<String, InputMethodInfo>();
145ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class SessionState {
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ClientState client;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final IInputMethod method;
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final IInputMethodSession session;
150ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "SessionState{uid " + client.uid + " pid " + client.pid
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " method " + Integer.toHexString(
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            System.identityHashCode(method))
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " session " + Integer.toHexString(
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            System.identityHashCode(session))
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + "}";
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SessionState(ClientState _client, IInputMethod _method,
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                IInputMethodSession _session) {
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            client = _client;
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            method = _method;
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            session = _session;
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
168ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class ClientState {
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final IInputMethodClient client;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final IInputContext inputContext;
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int uid;
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int pid;
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final InputBinding binding;
175ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean sessionRequested;
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SessionState curSession;
178ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "ClientState{" + Integer.toHexString(
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    System.identityHashCode(this)) + " uid " + uid
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " pid " + pid + "}";
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ClientState(IInputMethodClient _client, IInputContext _inputContext,
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int _uid, int _pid) {
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            client = _client;
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            inputContext = _inputContext;
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uid = _uid;
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pid = _pid;
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
195ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final HashMap<IBinder, ClientState> mClients
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            = new HashMap<IBinder, ClientState>();
198ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
200a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn     * Set once the system is ready to run third party code.
201a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn     */
202a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn    boolean mSystemReady;
203ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
204a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn    /**
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Id of the currently selected input method.
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    String mCurMethodId;
208ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The current binding sequence number, incremented every time there is
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * a new bind performed.
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int mCurSeq;
214ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The client that is currently bound to an input method.
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ClientState mCurClient;
219ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
221b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project     * The last window token that gained focus.
222b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project     */
223b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    IBinder mCurFocusedWindow;
224ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
225b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    /**
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The input context last provided by the current client.
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    IInputContext mCurInputContext;
229ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The attributes last provided by the current client.
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EditorInfo mCurAttribute;
234ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The input method ID of the input method service that we are currently
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * connected to or in the process of connecting to.
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    String mCurId;
240ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
242ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * The current subtype of the current input method.
243ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     */
244ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private InputMethodSubtype mCurrentSubtype;
245ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2464e4569dab5c75804b01a19b2d6e6101b445c1c68satok    // This list contains the pairs of InputMethodInfo and InputMethodSubtype.
247f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok    private final HashMap<InputMethodInfo, ArrayList<InputMethodSubtype>>
248f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            mShortcutInputMethodsAndSubtypes =
249f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                new HashMap<InputMethodInfo, ArrayList<InputMethodSubtype>>();
250ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
251ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    /**
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set to true if our ServiceConnection is currently actively bound to
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * a service (whether or not we have gotten its IBinder back yet).
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mHaveConnection;
256ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set if the client has asked for the input method to be shown.
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mShowRequested;
261ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set if we were explicitly told to show the input method.
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mShowExplicitlyRequested;
266ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set if we were forced to be shown.
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mShowForced;
271ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set if we last told the input method to show itself.
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mInputShown;
276ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The Intent used to connect to the current input method.
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Intent mCurIntent;
281ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The token we have made for the currently active input method, to
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * identify it in the future.
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    IBinder mCurToken;
287ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If non-null, this is the input method service we are currently connected
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to.
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    IInputMethod mCurMethod;
293ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Time that we last initiated a bind to the input method, to determine
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * if we should try to disconnect and reconnect to it.
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long mLastBindTime;
299ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Have we called mCurMethod.bindInput()?
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mBoundToMethod;
304ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Currently enabled session.  Only touched by service thread, not
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * protected by a lock.
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SessionState mEnabledSession;
310ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * True if the screen is on.  The value is true initially.
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mScreenOn = true;
315ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
316857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato    int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
317857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato    int mImeWindowVis;
3184d733290a112fbe7ca5631ee870094b538f39d80satok    long mOldSystemSettingsVersion;
319857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    AlertDialog.Builder mDialogBuilder;
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    AlertDialog mSwitchingDialog;
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    InputMethodInfo[] mIms;
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    CharSequence[] mItems;
324ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    int[] mSubtypeIds;
325ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class SettingsObserver extends ContentObserver {
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SettingsObserver(Handler handler) {
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(handler);
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ContentResolver resolver = mContext.getContentResolver();
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            resolver.registerContentObserver(Settings.Secure.getUriFor(
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
332ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            resolver.registerContentObserver(Settings.Secure.getUriFor(
333b6109bb591bc02bf8a2d9d5ca76d69d1961c9b5fsatok                    Settings.Secure.ENABLED_INPUT_METHODS), false, this);
334b6109bb591bc02bf8a2d9d5ca76d69d1961c9b5fsatok            resolver.registerContentObserver(Settings.Secure.getUriFor(
335ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this);
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
337ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override public void onChange(boolean selfChange) {
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                updateFromSettingsLocked();
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
344ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class ScreenOnOffReceiver extends android.content.BroadcastReceiver {
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mScreenOn = true;
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mScreenOn = false;
352105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            } else if (intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
353105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                hideInputMethodMenu();
354105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                return;
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
3568a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Unexpected intent " + intent);
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Inform the current client of the change in active status
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient != null && mCurClient.client != null) {
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCurClient.client.setActive(mScreenOn);
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
3658a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Got RemoteException sending 'screen on/off' notification to pid "
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + mCurClient.pid + " uid " + mCurClient.uid);
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
370ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
37121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    class MyPackageMonitor extends PackageMonitor {
37221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
37421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
37521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            synchronized (mMethodMap) {
37621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                String curInputMethodId = Settings.Secure.getString(mContext
37721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
37821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                final int N = mMethodList.size();
37921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                if (curInputMethodId != null) {
38021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    for (int i=0; i<N; i++) {
38121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        InputMethodInfo imi = mMethodList.get(i);
38221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        if (imi.getId().equals(curInputMethodId)) {
38321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            for (String pkg : packages) {
38421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                if (imi.getPackageName().equals(pkg)) {
38521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    if (!doit) {
38621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                        return true;
38721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    }
388723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                                    resetSelectedInputMethodAndSubtypeLocked("");
38921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    chooseNewDefaultIMELocked();
39021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    return true;
39121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                }
39221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            }
39321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        }
39421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    }
39508675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                }
39608675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu            }
39721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            return false;
39821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        }
399ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
40021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        @Override
40121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        public void onSomePackagesChanged() {
40221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            synchronized (mMethodMap) {
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                InputMethodInfo curIm = null;
40421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                String curInputMethodId = Settings.Secure.getString(mContext
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int N = mMethodList.size();
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (curInputMethodId != null) {
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (int i=0; i<N; i++) {
40921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        InputMethodInfo imi = mMethodList.get(i);
41021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        if (imi.getId().equals(curInputMethodId)) {
41121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            curIm = imi;
41221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        }
41321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        int change = isPackageDisappearing(imi.getPackageName());
41421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        if (change == PACKAGE_TEMPORARY_CHANGE
41521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                || change == PACKAGE_PERMANENT_CHANGE) {
4168a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            Slog.i(TAG, "Input method uninstalled, disabling: "
41721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    + imi.getComponent());
41821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            setInputMethodEnabledLocked(imi.getId(), false);
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
422ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
42321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                buildInputMethodListLocked(mMethodList, mMethodMap);
42421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean changed = false;
426ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
42708675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                if (curIm != null) {
42821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    int change = isPackageDisappearing(curIm.getPackageName());
42921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    if (change == PACKAGE_TEMPORARY_CHANGE
43021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            || change == PACKAGE_PERMANENT_CHANGE) {
43108675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        ServiceInfo si = null;
43208675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        try {
43308675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                            si = mContext.getPackageManager().getServiceInfo(
43408675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                                    curIm.getComponent(), 0);
43508675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        } catch (PackageManager.NameNotFoundException ex) {
43608675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        }
43708675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        if (si == null) {
43808675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                            // Uh oh, current input method is no longer around!
43908675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                            // Pick another one...
4408a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            Slog.i(TAG, "Current input method removed: " + curInputMethodId);
441857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                            mImeWindowVis = 0;
442857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                            mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis,
443857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                                    mBackDisposition);
44421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            if (!chooseNewDefaultIMELocked()) {
44508675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                                changed = true;
44608675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                                curIm = null;
4478a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                                Slog.i(TAG, "Unsetting current input method");
448723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                                resetSelectedInputMethodAndSubtypeLocked("");
44908675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                            }
45008675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        }
45108675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                    }
45221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                }
453ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
45421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                if (curIm == null) {
45521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    // We currently don't have a default input method... is
45621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    // one now available?
45721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    changed = chooseNewDefaultIMELocked();
45821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                }
459ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
46021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                if (changed) {
46121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    updateFromSettingsLocked();
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
466ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class MethodCallback extends IInputMethodCallback.Stub {
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final IInputMethod mMethod;
469ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MethodCallback(IInputMethod method) {
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMethod = method;
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
473ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void finishedEvent(int seq, boolean handled) throws RemoteException {
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void sessionCreated(IInputMethodSession session) throws RemoteException {
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            onSessionCreated(mMethod, session);
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
481ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
482089de88fc2f08d284cf8031aa33cff06011a4162Joe Onorato    public InputMethodManagerService(Context context, StatusBarManagerService statusBar) {
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
4847d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn        mRes = context.getResources();
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler = new Handler(this);
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIWindowManager = IWindowManager.Stub.asInterface(
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ServiceManager.getService(Context.WINDOW_SERVICE));
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCaller = new HandlerCaller(context, new HandlerCaller.Callback() {
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void executeMessage(Message msg) {
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handleMessage(msg);
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        });
4934d733290a112fbe7ca5631ee870094b538f39d80satok        // Initialize the system settings version to undefined.
4944d733290a112fbe7ca5631ee870094b538f39d80satok        mOldSystemSettingsVersion = -1;
495ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
49621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        (new MyPackageMonitor()).register(mContext, true);
497ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IntentFilter screenOnOffFilt = new IntentFilter();
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        screenOnOffFilt.addAction(Intent.ACTION_SCREEN_ON);
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        screenOnOffFilt.addAction(Intent.ACTION_SCREEN_OFF);
501105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        screenOnOffFilt.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.registerReceiver(new ScreenOnOffReceiver(), screenOnOffFilt);
503ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
504913a8925c07e854a80bf5df87561f290d3a56d61satok        mStatusBar = statusBar;
505913a8925c07e854a80bf5df87561f290d3a56d61satok        statusBar.setIconVisibility("ime", false);
506913a8925c07e854a80bf5df87561f290d3a56d61satok
507d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // mSettings should be created before buildInputMethodListLocked
508df31ae6a3011d47421a6ac10021f9649dc34a156satok        mSettings = new InputMethodSettings(
509df31ae6a3011d47421a6ac10021f9649dc34a156satok                mRes, context.getContentResolver(), mMethodMap, mMethodList);
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        buildInputMethodListLocked(mMethodList, mMethodMap);
511d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        mSettings.enableAllIMEsIfThereIsNoEnabledIME();
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
513d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        if (TextUtils.isEmpty(Settings.Secure.getString(
514d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD))) {
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            InputMethodInfo defIm = null;
516d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            for (InputMethodInfo imi: mMethodList) {
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (defIm == null && imi.getIsDefaultResourceId() != 0) {
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
519d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                        Resources res = context.createPackageContext(
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                imi.getPackageName(), 0).getResources();
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (res.getBoolean(imi.getIsDefaultResourceId())) {
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            defIm = imi;
5238a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            Slog.i(TAG, "Selected default: " + imi.getId());
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (PackageManager.NameNotFoundException ex) {
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (Resources.NotFoundException ex) {
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
530d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (defIm == null && mMethodList.size() > 0) {
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                defIm = mMethodList.get(0);
5328a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.i(TAG, "No default found, using " + defIm.getId());
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (defIm != null) {
535723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
538ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSettingsObserver = new SettingsObserver(mHandler);
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        updateFromSettingsLocked();
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws RemoteException {
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return super.onTransact(code, data, reply, flags);
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (RuntimeException e) {
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // The input method manager only throws security exceptions, so let's
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // log all others.
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!(e instanceof SecurityException)) {
5528a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.e(TAG, "Input Method Manager Crash", e);
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw e;
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void systemReady() {
559a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        synchronized (mMethodMap) {
560a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            if (!mSystemReady) {
561a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn                mSystemReady = true;
562cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                try {
563cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                    startInputInnerLocked();
564cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                } catch (RuntimeException e) {
5658a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.w(TAG, "Unexpected exception", e);
566cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                }
567a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            }
568a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        }
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
570ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public List<InputMethodInfo> getInputMethodList() {
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new ArrayList<InputMethodInfo>(mMethodList);
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public List<InputMethodInfo> getEnabledInputMethodList() {
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
579d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return mSettings.getEnabledInputMethodListLocked();
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
583bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok    private HashMap<InputMethodInfo, List<InputMethodSubtype>>
584bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            getExplicitlyOrImplicitlyEnabledInputMethodsAndSubtypeListLocked() {
585bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        HashMap<InputMethodInfo, List<InputMethodSubtype>> enabledInputMethodAndSubtypes =
586bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                new HashMap<InputMethodInfo, List<InputMethodSubtype>>();
587bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        for (InputMethodInfo imi: getEnabledInputMethodList()) {
588bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            enabledInputMethodAndSubtypes.put(
589bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                    imi, getEnabledInputMethodSubtypeListLocked(imi, true));
590bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        }
591bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        return enabledInputMethodAndSubtypes;
592bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok    }
593bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok
594bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok    public List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(InputMethodInfo imi,
595bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            boolean allowsImplicitlySelectedSubtypes) {
596bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        if (imi == null && mCurMethodId != null) {
597bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            imi = mMethodMap.get(mCurMethodId);
598bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        }
5997265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        List<InputMethodSubtype> enabledSubtypes =
600bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                mSettings.getEnabledInputMethodSubtypeListLocked(imi);
6017265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        if (allowsImplicitlySelectedSubtypes && enabledSubtypes.isEmpty()) {
6027265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok            enabledSubtypes = getApplicableSubtypesLocked(mRes, getSubtypes(imi));
603bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        }
6047265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        return InputMethodSubtype.sort(mContext, 0, imi, enabledSubtypes);
605bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok    }
606bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok
60716331c8a1d33defccc5cbb18694def79196c921bsatok    public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
60816331c8a1d33defccc5cbb18694def79196c921bsatok            boolean allowsImplicitlySelectedSubtypes) {
60967ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok        synchronized (mMethodMap) {
610bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            return getEnabledInputMethodSubtypeListLocked(imi, allowsImplicitlySelectedSubtypes);
61167ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok        }
61267ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok    }
61367ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addClient(IInputMethodClient client,
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            IInputContext inputContext, int uid, int pid) {
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClients.put(client.asBinder(), new ClientState(client,
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    inputContext, uid, pid));
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
621ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void removeClient(IInputMethodClient client) {
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClients.remove(client.asBinder());
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
627ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void executeOrSendMessage(IInterface target, Message msg) {
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         if (target.asBinder() instanceof Binder) {
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             mCaller.sendMessage(msg);
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         } else {
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             handleMessage(msg);
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             msg.recycle();
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         }
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
636ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
637b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    void unbindCurrentClientLocked() {
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurClient != null) {
6398a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client = "
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + mCurClient.client.asBinder());
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mBoundToMethod) {
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBoundToMethod = false;
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurMethod != null) {
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            MSG_UNBIND_INPUT, mCurMethod));
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurClient.sessionRequested = false;
651ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Call setActive(false) on the old client
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mCurClient.client.setActive(false);
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
6568a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + mCurClient.pid + " uid " + mCurClient.uid);
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurClient = null;
660ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
661105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            hideInputMethodMenuLocked();
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
664ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getImeShowFlags() {
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int flags = 0;
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mShowForced) {
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags |= InputMethod.SHOW_FORCED
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    | InputMethod.SHOW_EXPLICIT;
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (mShowExplicitlyRequested) {
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags |= InputMethod.SHOW_EXPLICIT;
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return flags;
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
675ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getAppShowFlags() {
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int flags = 0;
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mShowForced) {
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags |= InputMethodManager.SHOW_FORCED;
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (!mShowExplicitlyRequested) {
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags |= InputMethodManager.SHOW_IMPLICIT;
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return flags;
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
685ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    InputBindResult attachNewInputLocked(boolean initial, boolean needResult) {
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mBoundToMethod) {
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mBoundToMethod = true;
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final SessionState session = mCurClient.curSession;
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (initial) {
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            executeOrSendMessage(session.method, mCaller.obtainMessageOOO(
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MSG_START_INPUT, session, mCurInputContext, mCurAttribute));
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            executeOrSendMessage(session.method, mCaller.obtainMessageOOO(
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MSG_RESTART_INPUT, session, mCurInputContext, mCurAttribute));
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mShowRequested) {
7018a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
7024df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            showCurrentInputLocked(getAppShowFlags(), null);
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return needResult
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ? new InputBindResult(session.session, mCurId, mCurSeq)
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                : null;
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
708ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    InputBindResult startInputLocked(IInputMethodClient client,
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            IInputContext inputContext, EditorInfo attribute,
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean initial, boolean needResult) {
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // If no method is currently selected, do nothing.
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurMethodId == null) {
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mNoBinding;
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
716ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ClientState cs = mClients.get(client.asBinder());
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (cs == null) {
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("unknown client "
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + client.asBinder());
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
722ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mIWindowManager.inputMethodClientHasFocus(cs.client)) {
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Check with the window manager to make sure this client actually
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // has a window with focus.  If not, reject.  This is thread safe
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // because if the focus changes some time before or after, the
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // next client receiving focus that has any interest in input will
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // be calling through here after that change happens.
7308a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Starting input on non-focused client " + cs.client
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (RemoteException e) {
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
736ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurClient != cs) {
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If the client is changing, we need to switch over to the new
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // one.
740b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            unbindCurrentClientLocked();
7418a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG, "switching to client: client = "
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + cs.client.asBinder());
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If the screen is on, inform the new client it is active
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mScreenOn) {
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    cs.client.setActive(mScreenOn);
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
7498a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.w(TAG, "Got RemoteException sending setActive notification to pid "
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            + cs.pid + " uid " + cs.uid);
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
754ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Bump up the sequence for this client and attach it.
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurSeq++;
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurSeq <= 0) mCurSeq = 1;
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurClient = cs;
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurInputContext = inputContext;
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurAttribute = attribute;
761ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check if the input method is changing.
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurId != null && mCurId.equals(mCurMethodId)) {
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (cs.curSession != null) {
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Fast case: if we are already connected to the input method,
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // then just return it.
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return attachNewInputLocked(initial, needResult);
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mHaveConnection) {
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurMethod != null) {
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!cs.sessionRequested) {
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        cs.sessionRequested = true;
7738a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                        if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                MSG_CREATE_SESSION, mCurMethod,
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                new MethodCallback(mCurMethod)));
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Return to client, and we will get back with it when
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // we have had a session made for it.
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return new InputBindResult(null, mCurId, mCurSeq);
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (SystemClock.uptimeMillis()
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        < (mLastBindTime+TIME_TO_RECONNECT)) {
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // In this case we have connected to the service, but
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // don't yet have its interface.  If it hasn't been too
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // long since we did the connection, we'll return to
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // the client and wait to get the service interface so
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // we can report back.  If it has been too long, we want
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // to fall through so we can try a disconnect/reconnect
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // to see if we can get back in touch with the service.
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return new InputBindResult(null, mCurId, mCurSeq);
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
792ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker                    EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
793ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker                            mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
797ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
798a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        return startInputInnerLocked();
799a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn    }
800ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
801a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn    InputBindResult startInputInnerLocked() {
802a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        if (mCurMethodId == null) {
803a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            return mNoBinding;
804a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        }
805ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
806a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        if (!mSystemReady) {
807a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            // If the system is not yet ready, we shouldn't be running third
808a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            // party code.
809cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn            return new InputBindResult(null, mCurMethodId, mCurSeq);
810a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        }
811ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        InputMethodInfo info = mMethodMap.get(mCurMethodId);
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (info == null) {
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
816ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
817b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        unbindCurrentMethodLocked(false);
818ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurIntent.setComponent(info.getComponent());
821dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackborn        mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
822dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackborn                com.android.internal.R.string.input_method_binding_label);
823dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackborn        mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
824dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackborn                mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE)) {
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLastBindTime = SystemClock.uptimeMillis();
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHaveConnection = true;
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurId = info.getId();
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurToken = new Binder();
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
8318a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurToken);
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mIWindowManager.addWindowToken(mCurToken,
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        WindowManager.LayoutParams.TYPE_INPUT_METHOD);
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new InputBindResult(null, mCurId, mCurSeq);
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurIntent = null;
8398a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            Slog.w(TAG, "Failure connecting to input method service: "
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + mCurIntent);
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
844ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public InputBindResult startInput(IInputMethodClient client,
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            IInputContext inputContext, EditorInfo attribute,
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean initial, boolean needResult) {
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final long ident = Binder.clearCallingIdentity();
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return startInputLocked(client, inputContext, attribute,
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        initial, needResult);
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Binder.restoreCallingIdentity(ident);
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
858ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void finishInput(IInputMethodClient client) {
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
861ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onServiceConnected(ComponentName name, IBinder service) {
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mCurMethod = IInputMethod.Stub.asInterface(service);
866cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                if (mCurToken == null) {
8678a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.w(TAG, "Service connected without a token!");
868cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                    unbindCurrentMethodLocked(false);
869cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                    return;
870cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                }
8718a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
872cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
873cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                        MSG_ATTACH_TOKEN, mCurMethod, mCurToken));
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient != null) {
8758a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.v(TAG, "Creating first session while with client "
876cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                            + mCurClient);
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
878cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                            MSG_CREATE_SESSION, mCurMethod,
879cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                            new MethodCallback(mCurMethod)));
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void onSessionCreated(IInputMethod method, IInputMethodSession session) {
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mCurMethod != null && method != null
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && mCurMethod.asBinder() == method.asBinder()) {
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient != null) {
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCurClient.curSession = new SessionState(mCurClient,
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            method, session);
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCurClient.sessionRequested = false;
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    InputBindResult res = attachNewInputLocked(true, true);
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (res.method != null) {
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                MSG_BIND_METHOD, mCurClient.client, res));
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
902ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
903b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    void unbindCurrentMethodLocked(boolean reportToClient) {
904b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        if (mHaveConnection) {
905b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            mContext.unbindService(this);
906b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            mHaveConnection = false;
907b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        }
908ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
909b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        if (mCurToken != null) {
910b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            try {
9118a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Removing window token: " + mCurToken);
912b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                mIWindowManager.removeWindowToken(mCurToken);
913b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            } catch (RemoteException e) {
914b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            }
915b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            mCurToken = null;
916b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        }
917ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
918105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mCurId = null;
919b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        clearCurMethodLocked();
920ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
921b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        if (reportToClient && mCurClient != null) {
922b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
923b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
924b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        }
925b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    }
926b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
9270c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor    private void finishSession(SessionState sessionState) {
9280c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor        if (sessionState != null && sessionState.session != null) {
9290c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            try {
9300c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor                sessionState.session.finishSession();
9310c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            } catch (RemoteException e) {
9329d0f6dfdc1ac0b9374acf51572f273e9c9bbc9f9Jean-Baptiste Queru                Slog.w(TAG, "Session failed to close due to remote exception", e);
9330c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            }
9340c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor        }
9350c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor    }
936ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
937b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    void clearCurMethodLocked() {
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurMethod != null) {
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (ClientState cs : mClients.values()) {
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                cs.sessionRequested = false;
9410c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor                finishSession(cs.curSession);
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                cs.curSession = null;
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9440c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor
9450c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            finishSession(mEnabledSession);
9460c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            mEnabledSession = null;
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurMethod = null;
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9490cbda99f8721ad9b03ada04d2637fb75a2a0fecaJoe Onorato        mStatusBar.setIconVisibility("ime", false);
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
951ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onServiceDisconnected(ComponentName name) {
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
9548a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG, "Service disconnected: " + name
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mCurIntent=" + mCurIntent);
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mCurMethod != null && mCurIntent != null
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && name.equals(mCurIntent.getComponent())) {
958b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                clearCurMethodLocked();
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // We consider this to be a new bind attempt, since the system
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // should now try to restart the service for us.
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLastBindTime = SystemClock.uptimeMillis();
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mShowRequested = mInputShown;
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mInputShown = false;
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient != null) {
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void updateStatusIcon(IBinder token, String packageName, int iconId) {
973cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn        int uid = Binder.getCallingUid();
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long ident = Binder.clearCallingIdentity();
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (token == null || mCurToken != token) {
977cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                Slog.w(TAG, "Ignoring setInputMethod of uid " + uid + " token: " + token);
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
980ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (iconId == 0) {
9838a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
9840cbda99f8721ad9b03ada04d2637fb75a2a0fecaJoe Onorato                    mStatusBar.setIconVisibility("ime", false);
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (packageName != null) {
9868a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
9870cbda99f8721ad9b03ada04d2637fb75a2a0fecaJoe Onorato                    mStatusBar.setIcon("ime", packageName, iconId, 0);
9880cbda99f8721ad9b03ada04d2637fb75a2a0fecaJoe Onorato                    mStatusBar.setIconVisibility("ime", true);
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
996857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato    public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
99706487a58be22b100daf3f950b9a1d25c3ea42aa2satok        int uid = Binder.getCallingUid();
99806487a58be22b100daf3f950b9a1d25c3ea42aa2satok        long ident = Binder.clearCallingIdentity();
99906487a58be22b100daf3f950b9a1d25c3ea42aa2satok        try {
100006487a58be22b100daf3f950b9a1d25c3ea42aa2satok            if (token == null || mCurToken != token) {
1001857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                Slog.w(TAG, "Ignoring setImeWindowStatus of uid " + uid + " token: " + token);
100206487a58be22b100daf3f950b9a1d25c3ea42aa2satok                return;
100306487a58be22b100daf3f950b9a1d25c3ea42aa2satok            }
100406487a58be22b100daf3f950b9a1d25c3ea42aa2satok
100506487a58be22b100daf3f950b9a1d25c3ea42aa2satok            synchronized (mMethodMap) {
1006857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                mImeWindowVis = vis;
1007857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                mBackDisposition = backDisposition;
1008857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                mStatusBar.setImeWindowStatus(token, vis, backDisposition);
100906487a58be22b100daf3f950b9a1d25c3ea42aa2satok            }
101006487a58be22b100daf3f950b9a1d25c3ea42aa2satok        } finally {
101106487a58be22b100daf3f950b9a1d25c3ea42aa2satok            Binder.restoreCallingIdentity(ident);
101206487a58be22b100daf3f950b9a1d25c3ea42aa2satok        }
101306487a58be22b100daf3f950b9a1d25c3ea42aa2satok    }
101406487a58be22b100daf3f950b9a1d25c3ea42aa2satok
10154d733290a112fbe7ca5631ee870094b538f39d80satok    // TODO: Investigate and fix why are settings changes getting processed before the settings seq
10164d733290a112fbe7ca5631ee870094b538f39d80satok    // number is updated?
10174d733290a112fbe7ca5631ee870094b538f39d80satok    // TODO: Change this stuff to not rely on modifying settings for normal user interactions.
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void updateFromSettingsLocked() {
10194d733290a112fbe7ca5631ee870094b538f39d80satok        long newSystemSettingsVersion = getSystemSettingsVersion();
10204d733290a112fbe7ca5631ee870094b538f39d80satok        // This is a workaround to avoid a situation that old cached value in Settings.Secure
10214d733290a112fbe7ca5631ee870094b538f39d80satok        // will be handled.
10224d733290a112fbe7ca5631ee870094b538f39d80satok        if (newSystemSettingsVersion == mOldSystemSettingsVersion) return;
10234d733290a112fbe7ca5631ee870094b538f39d80satok
1024b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and
1025b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        // ENABLED_INPUT_METHODS is taking care of keeping them correctly in
1026b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        // sync, so we will never have a DEFAULT_INPUT_METHOD that is not
1027b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        // enabled.
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String id = Settings.Secure.getString(mContext.getContentResolver(),
1029ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                Settings.Secure.DEFAULT_INPUT_METHOD);
103003eb319a3a7fe6fe9ab9eba6fc1f727285850906satok        // There is no input method selected, try to choose new applicable input method.
103103eb319a3a7fe6fe9ab9eba6fc1f727285850906satok        if (TextUtils.isEmpty(id) && chooseNewDefaultIMELocked()) {
103203eb319a3a7fe6fe9ab9eba6fc1f727285850906satok            id = Settings.Secure.getString(mContext.getContentResolver(),
103303eb319a3a7fe6fe9ab9eba6fc1f727285850906satok                    Settings.Secure.DEFAULT_INPUT_METHOD);
103403eb319a3a7fe6fe9ab9eba6fc1f727285850906satok        }
103503eb319a3a7fe6fe9ab9eba6fc1f727285850906satok        if (!TextUtils.isEmpty(id)) {
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
1037ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                setInputMethodLocked(id, getSelectedInputMethodSubtypeId(id));
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IllegalArgumentException e) {
10398a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Unknown input method from prefs: " + id, e);
1040105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                mCurMethodId = null;
1041b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                unbindCurrentMethodLocked(true);
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1043f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            mShortcutInputMethodsAndSubtypes.clear();
1044b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        } else {
1045b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            // There is no longer an input method set, so stop any current one.
1046105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mCurMethodId = null;
1047b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            unbindCurrentMethodLocked(true);
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1050ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1051ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    /* package */ void setInputMethodLocked(String id, int subtypeId) {
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        InputMethodInfo info = mMethodMap.get(id);
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (info == null) {
1054913a8925c07e854a80bf5df87561f290d3a56d61satok            throw new IllegalArgumentException("Unknown id: " + id);
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1056ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (id.equals(mCurMethodId)) {
1058cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            InputMethodSubtype subtype = null;
1059586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa            if (subtypeId >= 0 && subtypeId < info.getSubtypeCount()) {
1060586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                subtype = info.getSubtypeAt(subtypeId);
1061cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            }
1062cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            if (subtype != mCurrentSubtype) {
1063cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                synchronized (mMethodMap) {
1064ca83021e3555e8b2bd07ded7885dc44053cd1a25satok                    if (subtype != null) {
1065ca83021e3555e8b2bd07ded7885dc44053cd1a25satok                        setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
1066ca83021e3555e8b2bd07ded7885dc44053cd1a25satok                    }
1067cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    if (mCurMethod != null) {
1068cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                        try {
1069e40dea0d06ec1c04db80191fd2965363b4fac781satok                            final Configuration conf = mRes.getConfiguration();
1070e40dea0d06ec1c04db80191fd2965363b4fac781satok                            final boolean haveHardKeyboard = conf.keyboard
1071e40dea0d06ec1c04db80191fd2965363b4fac781satok                                    != Configuration.KEYBOARD_NOKEYS;
1072e40dea0d06ec1c04db80191fd2965363b4fac781satok                            final boolean hardKeyShown = haveHardKeyboard
10738710e76a897cd546a79ee4338a4147eeb9f3e068Ken Wakasa                                    && conf.hardKeyboardHidden
10748710e76a897cd546a79ee4338a4147eeb9f3e068Ken Wakasa                                            != Configuration.HARDKEYBOARDHIDDEN_YES;
1075e40dea0d06ec1c04db80191fd2965363b4fac781satok                            mImeWindowVis = (mInputShown || hardKeyShown) ? (
1076e40dea0d06ec1c04db80191fd2965363b4fac781satok                                    InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE)
1077e40dea0d06ec1c04db80191fd2965363b4fac781satok                                    : 0;
1078857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                            mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis,
1079857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                                    mBackDisposition);
1080cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                            // If subtype is null, try to find the most applicable one from
1081cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                            // getCurrentInputMethodSubtype.
1082cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                            if (subtype == null) {
1083cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                                subtype = getCurrentInputMethodSubtype();
1084ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                            }
1085cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                            mCurMethod.changeInputMethodSubtype(subtype);
1086cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                        } catch (RemoteException e) {
1087cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                            return;
1088ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                        }
1089ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    }
1090ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                }
1091ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            }
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1094ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long ident = Binder.clearCallingIdentity();
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
1097ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            // Set a subtype to this input method.
1098ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            // subtypeId the name of a subtype which will be set.
1099723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            setSelectedInputMethodAndSubtypeLocked(info, subtypeId, false);
1100723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
1101723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // because mCurMethodId is stored as a history in
1102723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // setSelectedInputMethodAndSubtypeLocked().
1103723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mCurMethodId = id;
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (ActivityManagerNative.isSystemReady()) {
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
11071c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                intent.putExtra("input_method_id", id);
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mContext.sendBroadcast(intent);
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1111b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            unbindCurrentClientLocked();
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1116ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11174df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    public boolean showSoftInput(IInputMethodClient client, int flags,
11184df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            ResultReceiver resultReceiver) {
1119cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn        int uid = Binder.getCallingUid();
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long ident = Binder.clearCallingIdentity();
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient == null || client == null
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        || mCurClient.client.asBinder() != client.asBinder()) {
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // We need to check if this is the current client with
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // focus in the window manager, to allow this call to
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // be made before input is started in it.
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (!mIWindowManager.inputMethodClientHasFocus(client)) {
1130cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                            Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
11314df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            return false;
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (RemoteException e) {
11344df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                        return false;
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1137ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11388a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
11394df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                return showCurrentInputLocked(flags, resultReceiver);
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1145ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11464df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    boolean showCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mShowRequested = true;
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mShowExplicitlyRequested = true;
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mShowExplicitlyRequested = true;
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mShowForced = true;
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1155ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1156cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn        if (!mSystemReady) {
1157cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn            return false;
1158cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn        }
1159ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11604df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        boolean res = false;
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurMethod != null) {
11624df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
11634df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod,
11644df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    resultReceiver));
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mInputShown = true;
11664df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            res = true;
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (mHaveConnection && SystemClock.uptimeMillis()
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                < (mLastBindTime+TIME_TO_RECONNECT)) {
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // The client has asked to have the input method shown, but
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // we have been sitting here too long with a connection to the
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // service and no interface received, so let's disconnect/connect
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // to try to prod things along.
1173ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker            EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId,
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SystemClock.uptimeMillis()-mLastBindTime,1);
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.unbindService(this);
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE);
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1178ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11794df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        return res;
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1181ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11824df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    public boolean hideSoftInput(IInputMethodClient client, int flags,
11834df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            ResultReceiver resultReceiver) {
1184cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn        int uid = Binder.getCallingUid();
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long ident = Binder.clearCallingIdentity();
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient == null || client == null
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        || mCurClient.client.asBinder() != client.asBinder()) {
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // We need to check if this is the current client with
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // focus in the window manager, to allow this call to
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // be made before input is started in it.
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (!mIWindowManager.inputMethodClientHasFocus(client)) {
1195cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                            if (DEBUG) Slog.w(TAG, "Ignoring hideSoftInput of uid "
1196cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                                    + uid + ": " + client);
1197857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                            mImeWindowVis = 0;
1198857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                            mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis,
1199857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                                    mBackDisposition);
12004df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            return false;
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (RemoteException e) {
1203857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                        mImeWindowVis = 0;
1204857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                        mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis, mBackDisposition);
12054df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                        return false;
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1208ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
12098a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
12104df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                return hideCurrentInputLocked(flags, resultReceiver);
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1216ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
12174df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                && (mShowExplicitlyRequested || mShowForced)) {
12208a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG,
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    "Not hiding: explicit show not cancelled by non-explicit hide");
12224df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            return false;
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
12258a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG,
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    "Not hiding: forced show not cancelled by not-always hide");
12274df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            return false;
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12294df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        boolean res;
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mInputShown && mCurMethod != null) {
12314df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
12324df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    MSG_HIDE_SOFT_INPUT, mCurMethod, resultReceiver));
12334df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            res = true;
12344df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        } else {
12354df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            res = false;
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mInputShown = false;
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mShowRequested = false;
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mShowExplicitlyRequested = false;
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mShowForced = false;
12414df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        return res;
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1243ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1244b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    public void windowGainedFocus(IInputMethodClient client, IBinder windowToken,
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean viewHasFocus, boolean isTextEditor, int softInputMode,
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean first, int windowFlags) {
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long ident = Binder.clearCallingIdentity();
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
12508a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "windowGainedFocus: " + client.asBinder()
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + " viewHasFocus=" + viewHasFocus
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + " isTextEditor=" + isTextEditor
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + " softInputMode=#" + Integer.toHexString(softInputMode)
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + " first=" + first + " flags=#"
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + Integer.toHexString(windowFlags));
1256ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient == null || client == null
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        || mCurClient.client.asBinder() != client.asBinder()) {
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // We need to check if this is the current client with
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // focus in the window manager, to allow this call to
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // be made before input is started in it.
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (!mIWindowManager.inputMethodClientHasFocus(client)) {
12648a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            Slog.w(TAG, "Client not active, ignoring focus gain of: " + client);
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            return;
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (RemoteException e) {
12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1270ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1271b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                if (mCurFocusedWindow == windowToken) {
12728a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client);
1273b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    return;
1274b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
1275b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                mCurFocusedWindow = windowToken;
1276ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
12777d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // Should we auto-show the IME even if the caller has not
12787d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // specified what should be done with it?
12797d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // We only do this automatically if the window can resize
12807d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // to accommodate the IME (so what the user sees will give
12817d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // them good context without input information being obscured
12827d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // by the IME) or if running on a large screen where there
12837d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // is more room for the target window + IME.
12847d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                final boolean doAutoShow =
12857d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                        (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
12867d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                                == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
12877d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                        || mRes.getConfiguration().isLayoutSizeAtLeast(
12887d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                                Configuration.SCREENLAYOUT_SIZE_LARGE);
12897d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
12927d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                        if (!isTextEditor || !doAutoShow) {
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (WindowManager.LayoutParams.mayUseInputMethod(windowFlags)) {
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                // There is no focus view, and this window will
12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                // be behind any soft input window, so hide the
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                // soft input window if it is shown.
12978a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                                if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
12984df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                                hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
13007d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                        } else if (isTextEditor && doAutoShow && (softInputMode &
13017d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // There is a focus view, and we are navigating forward
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // into the window, so show the input window for the user.
13047d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                            // We only do this automatically if the window an resize
13057d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                            // to accomodate the IME (so what the user sees will give
13067d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                            // them good context without input information being obscured
13077d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                            // by the IME) or if running on a large screen where there
13087d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                            // is more room for the target window + IME.
13098a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
13104df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // Do nothing.
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if ((softInputMode &
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
13198a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
13204df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            hideCurrentInputLocked(0, null);
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
13248a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                        if (DEBUG) Slog.v(TAG, "Window asks to hide input");
13254df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                        hideCurrentInputLocked(0, null);
13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if ((softInputMode &
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
13308a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
13314df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
13358a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                        if (DEBUG) Slog.v(TAG, "Window asks to always show input");
13364df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                        showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1344ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void showInputMethodPickerFromClient(IInputMethodClient client) {
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mCurClient == null || client == null
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    || mCurClient.client.asBinder() != client.asBinder()) {
134947a44916e2fb33cf4751906386d5f5c903b28d8bsatok                Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
1350cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                        + Binder.getCallingUid() + ": " + client);
13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1353440aab54cab106030f1edafea4dec1f9d8624f9bsatok            // Always call subtype picker, because subtype picker is a superset of input method
1354440aab54cab106030f1edafea4dec1f9d8624f9bsatok            // picker.
1355ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            mHandler.sendEmptyMessage(MSG_SHOW_IM_SUBTYPE_PICKER);
1356ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        }
1357ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
1358ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setInputMethod(IBinder token, String id) {
13602820351489537698ad153c6397edf3270455edc5satok        setInputMethodWithSubtypeId(token, id, NOT_A_SUBTYPE_ID);
13612820351489537698ad153c6397edf3270455edc5satok    }
13622820351489537698ad153c6397edf3270455edc5satok
13632820351489537698ad153c6397edf3270455edc5satok    public void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) {
13642820351489537698ad153c6397edf3270455edc5satok        synchronized (mMethodMap) {
13652820351489537698ad153c6397edf3270455edc5satok            if (subtype != null) {
13662820351489537698ad153c6397edf3270455edc5satok                setInputMethodWithSubtypeId(token, id, getSubtypeIdFromHashCode(
13672820351489537698ad153c6397edf3270455edc5satok                        mMethodMap.get(id), subtype.hashCode()));
13682820351489537698ad153c6397edf3270455edc5satok            } else {
13692820351489537698ad153c6397edf3270455edc5satok                setInputMethod(token, id);
13702820351489537698ad153c6397edf3270455edc5satok            }
13712820351489537698ad153c6397edf3270455edc5satok        }
1372ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
1373ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
1374b416a71e56cdd50742eb897366a140775aa4cd61satok    public void showInputMethodAndSubtypeEnablerFromClient(
1375217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok            IInputMethodClient client, String inputMethodId) {
1376b416a71e56cdd50742eb897366a140775aa4cd61satok        synchronized (mMethodMap) {
1377b416a71e56cdd50742eb897366a140775aa4cd61satok            if (mCurClient == null || client == null
1378b416a71e56cdd50742eb897366a140775aa4cd61satok                || mCurClient.client.asBinder() != client.asBinder()) {
1379b416a71e56cdd50742eb897366a140775aa4cd61satok                Slog.w(TAG, "Ignoring showInputMethodAndSubtypeEnablerFromClient of: " + client);
1380b416a71e56cdd50742eb897366a140775aa4cd61satok            }
13817fee71f66afef6421b92fa48e63d4bc73f5d0c27satok            executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
13827fee71f66afef6421b92fa48e63d4bc73f5d0c27satok                    MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
1383b416a71e56cdd50742eb897366a140775aa4cd61satok        }
1384b416a71e56cdd50742eb897366a140775aa4cd61satok    }
1385b416a71e56cdd50742eb897366a140775aa4cd61satok
1386735cf38b8c7f8f91ad087511e44fe79018fa61d6satok    public boolean switchToLastInputMethod(IBinder token) {
1387735cf38b8c7f8f91ad087511e44fe79018fa61d6satok        synchronized (mMethodMap) {
1388c445bcd0bce630948ee029d7c70b28226f0b6c9csatok            final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
1389c445bcd0bce630948ee029d7c70b28226f0b6c9csatok            if (lastIme == null) return false;
1390c445bcd0bce630948ee029d7c70b28226f0b6c9csatok            final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
1391c445bcd0bce630948ee029d7c70b28226f0b6c9csatok            if (lastImi == null) return false;
1392c445bcd0bce630948ee029d7c70b28226f0b6c9csatok
1393c445bcd0bce630948ee029d7c70b28226f0b6c9csatok            final boolean imiIdIsSame = lastImi.getId().equals(mCurMethodId);
1394c445bcd0bce630948ee029d7c70b28226f0b6c9csatok            final int lastSubtypeHash = Integer.valueOf(lastIme.second);
1395c445bcd0bce630948ee029d7c70b28226f0b6c9csatok            // If the last IME is the same as the current IME and the last subtype is not defined,
1396c445bcd0bce630948ee029d7c70b28226f0b6c9csatok            // there is no need to switch to the last IME.
1397c445bcd0bce630948ee029d7c70b28226f0b6c9csatok            if (imiIdIsSame && lastSubtypeHash == NOT_A_SUBTYPE_ID) return false;
1398c445bcd0bce630948ee029d7c70b28226f0b6c9csatok
1399c445bcd0bce630948ee029d7c70b28226f0b6c9csatok            int currentSubtypeHash = mCurrentSubtype == null ? NOT_A_SUBTYPE_ID
1400c445bcd0bce630948ee029d7c70b28226f0b6c9csatok                    : mCurrentSubtype.hashCode();
1401c445bcd0bce630948ee029d7c70b28226f0b6c9csatok            if (!imiIdIsSame || lastSubtypeHash != currentSubtypeHash) {
1402c445bcd0bce630948ee029d7c70b28226f0b6c9csatok                if (DEBUG) {
1403c445bcd0bce630948ee029d7c70b28226f0b6c9csatok                    Slog.d(TAG, "Switch to: " + lastImi.getId() + ", " + lastIme.second + ", from: "
1404c445bcd0bce630948ee029d7c70b28226f0b6c9csatok                            + mCurMethodId + ", " + currentSubtypeHash);
1405735cf38b8c7f8f91ad087511e44fe79018fa61d6satok                }
1406c445bcd0bce630948ee029d7c70b28226f0b6c9csatok                setInputMethodWithSubtypeId(token, lastIme.first, getSubtypeIdFromHashCode(
1407c445bcd0bce630948ee029d7c70b28226f0b6c9csatok                        lastImi, lastSubtypeHash));
1408c445bcd0bce630948ee029d7c70b28226f0b6c9csatok                return true;
1409735cf38b8c7f8f91ad087511e44fe79018fa61d6satok            }
1410735cf38b8c7f8f91ad087511e44fe79018fa61d6satok            return false;
1411735cf38b8c7f8f91ad087511e44fe79018fa61d6satok        }
1412735cf38b8c7f8f91ad087511e44fe79018fa61d6satok    }
1413735cf38b8c7f8f91ad087511e44fe79018fa61d6satok
14142820351489537698ad153c6397edf3270455edc5satok    private void setInputMethodWithSubtypeId(IBinder token, String id, int subtypeId) {
14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (token == null) {
14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mContext.checkCallingOrSelfPermission(
14189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        android.Manifest.permission.WRITE_SECURE_SETTINGS)
14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        != PackageManager.PERMISSION_GRANTED) {
14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    throw new SecurityException(
14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            "Using null token requires permission "
14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            + android.Manifest.permission.WRITE_SECURE_SETTINGS);
14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (mCurToken != token) {
1425cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
1426cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                        + " token: " + token);
14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long ident = Binder.clearCallingIdentity();
14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
1432ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                setInputMethodLocked(id, subtypeId);
14339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Binder.restoreCallingIdentity(ident);
14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void hideMySoftInput(IBinder token, int flags) {
14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (token == null || mCurToken != token) {
1442cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                if (DEBUG) Slog.w(TAG, "Ignoring hideInputMethod of uid "
1443cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                        + Binder.getCallingUid() + " token: " + token);
14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long ident = Binder.clearCallingIdentity();
14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
14484df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                hideCurrentInputLocked(flags, null);
14494df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            } finally {
14504df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                Binder.restoreCallingIdentity(ident);
14514df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            }
14524df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        }
14534df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    }
1454ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
14554df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    public void showMySoftInput(IBinder token, int flags) {
14564df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        synchronized (mMethodMap) {
14574df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            if (token == null || mCurToken != token) {
1458cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                Slog.w(TAG, "Ignoring showMySoftInput of uid "
1459cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                        + Binder.getCallingUid() + " token: " + token);
14604df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                return;
14614df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            }
14624df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            long ident = Binder.clearCallingIdentity();
14634df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            try {
14644df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                showCurrentInputLocked(flags, null);
14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Binder.restoreCallingIdentity(ident);
14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void setEnabledSessionInMainThread(SessionState session) {
14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnabledSession != session) {
14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mEnabledSession != null) {
14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
14758a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mEnabledSession.method.setSessionEnabled(
14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mEnabledSession.session, false);
14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEnabledSession = session;
14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
14838a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                session.method.setSessionEnabled(
14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        session.session, true);
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1490ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean handleMessage(Message msg) {
14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        HandlerCaller.SomeArgs args;
14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (msg.what) {
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_SHOW_IM_PICKER:
14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                showInputMethodMenu();
14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
1497ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1498ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            case MSG_SHOW_IM_SUBTYPE_PICKER:
1499ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                showInputMethodSubtypeMenu();
1500ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                return true;
1501ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
150247a44916e2fb33cf4751906386d5f5c903b28d8bsatok            case MSG_SHOW_IM_SUBTYPE_ENABLER:
1503217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                args = (HandlerCaller.SomeArgs)msg.obj;
15047fee71f66afef6421b92fa48e63d4bc73f5d0c27satok                showInputMethodAndSubtypeEnabler((String)args.arg1);
1505217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                return true;
1506217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok
1507217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok            case MSG_SHOW_IM_CONFIG:
1508217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                showConfigureInputMethods();
150947a44916e2fb33cf4751906386d5f5c903b28d8bsatok                return true;
151047a44916e2fb33cf4751906386d5f5c903b28d8bsatok
15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ---------------------------------------------------------
1512ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_UNBIND_INPUT:
15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethod)msg.obj).unbindInput();
15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // There is nothing interesting about the method dying.
15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_BIND_INPUT:
15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                args = (HandlerCaller.SomeArgs)msg.obj;
15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethod)args.arg1).bindInput((InputBinding)args.arg2);
15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_SHOW_SOFT_INPUT:
15284df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                args = (HandlerCaller.SomeArgs)msg.obj;
15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
15304df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    ((IInputMethod)args.arg1).showSoftInput(msg.arg1,
15314df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            (ResultReceiver)args.arg2);
15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_HIDE_SOFT_INPUT:
15364df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                args = (HandlerCaller.SomeArgs)msg.obj;
15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
15384df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    ((IInputMethod)args.arg1).hideSoftInput(0,
15394df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            (ResultReceiver)args.arg2);
15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_ATTACH_TOKEN:
15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                args = (HandlerCaller.SomeArgs)msg.obj;
15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
15468a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.v(TAG, "Sending attach of token: " + args.arg2);
15479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethod)args.arg1).attachToken((IBinder)args.arg2);
15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
15499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_CREATE_SESSION:
15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                args = (HandlerCaller.SomeArgs)msg.obj;
15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethod)args.arg1).createSession(
15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (IInputMethodCallback)args.arg2);
15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ---------------------------------------------------------
1560ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_START_INPUT:
15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                args = (HandlerCaller.SomeArgs)msg.obj;
15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SessionState session = (SessionState)args.arg1;
15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setEnabledSessionInMainThread(session);
15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    session.method.startInput((IInputContext)args.arg2,
15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (EditorInfo)args.arg3);
15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_RESTART_INPUT:
15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                args = (HandlerCaller.SomeArgs)msg.obj;
15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SessionState session = (SessionState)args.arg1;
15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setEnabledSessionInMainThread(session);
15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    session.method.restartInput((IInputContext)args.arg2,
15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (EditorInfo)args.arg3);
15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
1581ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ---------------------------------------------------------
1583ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_UNBIND_METHOD:
15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1);
15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // There is nothing interesting about the last client dying.
15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
15919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_BIND_METHOD:
15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                args = (HandlerCaller.SomeArgs)msg.obj;
15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethodClient)args.arg1).onBindMethod(
15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (InputBindResult)args.arg2);
15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
15978a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.w(TAG, "Client died receiving input method " + args.arg2);
15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16046da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger    private boolean isSystemIme(InputMethodInfo inputMethod) {
16056da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        return (inputMethod.getServiceInfo().applicationInfo.flags
16066da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger                & ApplicationInfo.FLAG_SYSTEM) != 0;
16076da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger    }
16086da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
1609586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa    private static ArrayList<InputMethodSubtype> getSubtypes(InputMethodInfo imi) {
1610586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
1611586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        final int subtypeCount = imi.getSubtypeCount();
1612586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        for (int i = 0; i < subtypeCount; ++i) {
1613586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa            subtypes.add(imi.getSubtypeAt(i));
1614586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        }
1615586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        return subtypes;
1616586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa    }
1617586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa
161821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    private boolean chooseNewDefaultIMELocked() {
1619d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
16206da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        if (enabled != null && enabled.size() > 0) {
162183e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn            // We'd prefer to fall back on a system IME, since that is safer.
162283e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn            int i=enabled.size();
162383e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn            while (i > 0) {
162483e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn                i--;
162583e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn                if ((enabled.get(i).getServiceInfo().applicationInfo.flags
162683e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn                        & ApplicationInfo.FLAG_SYSTEM) != 0) {
162783e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn                    break;
162883e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn                }
162983e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn            }
1630ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            InputMethodInfo imi = enabled.get(i);
163103eb319a3a7fe6fe9ab9eba6fc1f727285850906satok            if (DEBUG) {
163203eb319a3a7fe6fe9ab9eba6fc1f727285850906satok                Slog.d(TAG, "New default IME was selected: " + imi.getId());
163303eb319a3a7fe6fe9ab9eba6fc1f727285850906satok            }
1634723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            resetSelectedInputMethodAndSubtypeLocked(imi.getId());
16356da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger            return true;
16366da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        }
16376da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
16386da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        return false;
16396da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger    }
16406da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void buildInputMethodListLocked(ArrayList<InputMethodInfo> list,
16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            HashMap<String, InputMethodInfo> map) {
16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        list.clear();
16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.clear();
1645ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PackageManager pm = mContext.getPackageManager();
16477d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn        final Configuration config = mRes.getConfiguration();
1648e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani        final boolean haveHardKeyboard = config.keyboard == Configuration.KEYBOARD_QWERTY;
1649e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani        String disabledSysImes = Settings.Secure.getString(mContext.getContentResolver(),
1650e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani                Secure.DISABLED_SYSTEM_INPUT_METHODS);
1651e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani        if (disabledSysImes == null) disabledSysImes = "";
16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        List<ResolveInfo> services = pm.queryIntentServices(
16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                new Intent(InputMethod.SERVICE_INTERFACE),
16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                PackageManager.GET_META_DATA);
1656ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < services.size(); ++i) {
16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ResolveInfo ri = services.get(i);
16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ServiceInfo si = ri.serviceInfo;
16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ComponentName compName = new ComponentName(si.packageName, si.name);
16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!android.Manifest.permission.BIND_INPUT_METHOD.equals(
16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    si.permission)) {
16638a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Skipping input method " + compName
16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + ": it does not require the permission "
16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + android.Manifest.permission.BIND_INPUT_METHOD);
16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16698a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.d(TAG, "Checking " + compName);
16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                InputMethodInfo p = new InputMethodInfo(mContext, ri);
16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                list.add(p);
1674e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani                final String id = p.getId();
1675e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani                map.put(id, p);
16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1677e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani                // System IMEs are enabled by default, unless there's a hard keyboard
1678e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani                // and the system IME was explicitly disabled
1679e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani                if (isSystemIme(p) && (!haveHardKeyboard || disabledSysImes.indexOf(id) < 0)) {
1680e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani                    setInputMethodEnabledLocked(id, true);
16816da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger                }
16826da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
16839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (DEBUG) {
16848a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.d(TAG, "Found a third-party input method " + p);
16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1686ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (XmlPullParserException e) {
16888a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Unable to load input method " + compName, e);
16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IOException e) {
16908a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Unable to load input method " + compName, e);
16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16936da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
16946da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        String defaultIme = Settings.Secure.getString(mContext
16956da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger                .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
1696913a8925c07e854a80bf5df87561f290d3a56d61satok        if (!TextUtils.isEmpty(defaultIme) && !map.containsKey(defaultIme)) {
169721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            if (chooseNewDefaultIMELocked()) {
16986da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger                updateFromSettingsLocked();
16996da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger            }
17006da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        }
17019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1702ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
17039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ----------------------------------------------------------------------
1704ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1705ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private void showInputMethodMenu() {
1706ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        showInputMethodMenuInternal(false);
1707ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
1708ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
1709ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private void showInputMethodSubtypeMenu() {
1710ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        showInputMethodMenuInternal(true);
1711ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
1712ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
1713217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok    private void showInputMethodAndSubtypeEnabler(String inputMethodId) {
1714f49688fa17b70313c0734f00df73bc3308a749e9Tadashi G. Takaoka        Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
171547a44916e2fb33cf4751906386d5f5c903b28d8bsatok        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
171686417ea3f8041481a085823a1aa9f66d747231e8satok                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
171786417ea3f8041481a085823a1aa9f66d747231e8satok                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
17187fee71f66afef6421b92fa48e63d4bc73f5d0c27satok        if (!TextUtils.isEmpty(inputMethodId)) {
17192548020c364c4119d134c84cc7a00ffca2dcbe7bTadashi G. Takaoka            intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
17207fee71f66afef6421b92fa48e63d4bc73f5d0c27satok        }
1721217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok        mContext.startActivity(intent);
1722217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok    }
1723217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok
1724217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok    private void showConfigureInputMethods() {
1725217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok        Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
1726217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1727217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
1728217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
172947a44916e2fb33cf4751906386d5f5c903b28d8bsatok        mContext.startActivity(intent);
173047a44916e2fb33cf4751906386d5f5c903b28d8bsatok    }
173147a44916e2fb33cf4751906386d5f5c903b28d8bsatok
1732ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private void showInputMethodMenuInternal(boolean showSubtypes) {
17338a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        if (DEBUG) Slog.v(TAG, "Show switching menu");
17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Context context = mContext;
1736ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final PackageManager pm = context.getPackageManager();
1738ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String lastInputMethodId = Settings.Secure.getString(context
17409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
1741ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        int lastInputMethodSubtypeId = getSelectedInputMethodSubtypeId(lastInputMethodId);
17428a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
1743ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
17447f35c8cc88bea5230f001dd4356f864845d202e5satok        synchronized (mMethodMap) {
1745bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            final HashMap<InputMethodInfo, List<InputMethodSubtype>> immis =
1746bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                    getExplicitlyOrImplicitlyEnabledInputMethodsAndSubtypeListLocked();
17477f35c8cc88bea5230f001dd4356f864845d202e5satok            if (immis == null || immis.size() == 0) {
17487f35c8cc88bea5230f001dd4356f864845d202e5satok                return;
17497f35c8cc88bea5230f001dd4356f864845d202e5satok            }
1750ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
17518cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            hideInputMethodMenuLocked();
17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1753ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            final Map<CharSequence, Pair<InputMethodInfo, Integer>> imMap =
1754ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                new TreeMap<CharSequence, Pair<InputMethodInfo, Integer>>(Collator.getInstance());
1755913a8925c07e854a80bf5df87561f290d3a56d61satok
1756bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            for (InputMethodInfo imi: immis.keySet()) {
1757bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                if (imi == null) continue;
1758bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList = immis.get(imi);
17597f35c8cc88bea5230f001dd4356f864845d202e5satok                HashSet<String> enabledSubtypeSet = new HashSet<String>();
1760bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                for (InputMethodSubtype subtype: explicitlyOrImplicitlyEnabledSubtypeList) {
1761bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                    enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
17627f35c8cc88bea5230f001dd4356f864845d202e5satok                }
1763bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                ArrayList<InputMethodSubtype> subtypes = getSubtypes(imi);
1764bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                CharSequence label = imi.loadLabel(pm);
17657f35c8cc88bea5230f001dd4356f864845d202e5satok                if (showSubtypes && enabledSubtypeSet.size() > 0) {
1766bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                    final int subtypeCount = imi.getSubtypeCount();
1767586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                    for (int j = 0; j < subtypeCount; ++j) {
1768bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                        InputMethodSubtype subtype = imi.getSubtypeAt(j);
17697f35c8cc88bea5230f001dd4356f864845d202e5satok                        if (enabledSubtypeSet.contains(String.valueOf(subtype.hashCode()))) {
17707f35c8cc88bea5230f001dd4356f864845d202e5satok                            CharSequence title;
17717f35c8cc88bea5230f001dd4356f864845d202e5satok                            int nameResId = subtype.getNameResId();
17729ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                            String mode = subtype.getMode();
17737f35c8cc88bea5230f001dd4356f864845d202e5satok                            if (nameResId != 0) {
1774bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                                title = pm.getText(imi.getPackageName(), nameResId,
1775bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                                        imi.getServiceInfo().applicationInfo);
17767f35c8cc88bea5230f001dd4356f864845d202e5satok                            } else {
17777f35c8cc88bea5230f001dd4356f864845d202e5satok                                CharSequence language = subtype.getLocale();
17787f35c8cc88bea5230f001dd4356f864845d202e5satok                                // TODO: Use more friendly Title and UI
17797f35c8cc88bea5230f001dd4356f864845d202e5satok                                title = label + "," + (mode == null ? "" : mode) + ","
17807f35c8cc88bea5230f001dd4356f864845d202e5satok                                        + (language == null ? "" : language);
17817f35c8cc88bea5230f001dd4356f864845d202e5satok                            }
1782bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                            imMap.put(title, new Pair<InputMethodInfo, Integer>(imi, j));
1783ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                        }
1784ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    }
1785ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                } else {
1786ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    imMap.put(label,
1787bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                            new Pair<InputMethodInfo, Integer>(imi, NOT_A_SUBTYPE_ID));
1788ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                }
17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1790913a8925c07e854a80bf5df87561f290d3a56d61satok
1791bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            final int N = imMap.size();
1792913a8925c07e854a80bf5df87561f290d3a56d61satok            mItems = imMap.keySet().toArray(new CharSequence[N]);
1793ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            mIms = new InputMethodInfo[N];
1794ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            mSubtypeIds = new int[N];
17958cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            int checkedItem = 0;
17968cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            for (int i = 0; i < N; ++i) {
1797ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                Pair<InputMethodInfo, Integer> value = imMap.get(mItems[i]);
1798ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                mIms[i] = value.first;
1799ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                mSubtypeIds[i] = value.second;
18008cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                if (mIms[i].getId().equals(lastInputMethodId)) {
1801ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    int subtypeId = mSubtypeIds[i];
1802ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    if ((subtypeId == NOT_A_SUBTYPE_ID)
1803ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                            || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0)
1804ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                            || (subtypeId == lastInputMethodSubtypeId)) {
1805ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                        checkedItem = i;
1806ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    }
18078cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                }
18089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1809ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
18108cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            AlertDialog.OnClickListener adocl = new AlertDialog.OnClickListener() {
18118cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                public void onClick(DialogInterface dialog, int which) {
18128cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    hideInputMethodMenu();
18138cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                }
18148cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            };
1815d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
18168cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            TypedArray a = context.obtainStyledAttributes(null,
18178cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    com.android.internal.R.styleable.DialogPreference,
18188cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    com.android.internal.R.attr.alertDialogStyle, 0);
18198cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            mDialogBuilder = new AlertDialog.Builder(context)
18208cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    .setTitle(com.android.internal.R.string.select_input_method)
18218cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    .setOnCancelListener(new OnCancelListener() {
18228cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                        public void onCancel(DialogInterface dialog) {
18239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            hideInputMethodMenu();
18248cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                        }
18258cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    })
18268cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    .setIcon(a.getDrawable(
18278cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                            com.android.internal.R.styleable.DialogPreference_dialogTitle));
18288cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            a.recycle();
1829d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
18308cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            mDialogBuilder.setSingleChoiceItems(mItems, checkedItem,
18318cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    new AlertDialog.OnClickListener() {
18328cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                        public void onClick(DialogInterface dialog, int which) {
18338cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                            synchronized (mMethodMap) {
1834ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                if (mIms == null || mIms.length <= which
1835ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                        || mSubtypeIds == null || mSubtypeIds.length <= which) {
18368cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                    return;
18378cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                }
18388cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                InputMethodInfo im = mIms[which];
1839ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                int subtypeId = mSubtypeIds[which];
18408cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                hideInputMethodMenu();
18418cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                if (im != null) {
1842ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                    if ((subtypeId < 0)
1843586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                                            || (subtypeId >= im.getSubtypeCount())) {
1844ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                        subtypeId = NOT_A_SUBTYPE_ID;
1845ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                    }
1846ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                    setInputMethodLocked(im.getId(), subtypeId);
18478cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                }
184820cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn                            }
18499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
18508cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    });
18519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18527f35c8cc88bea5230f001dd4356f864845d202e5satok            if (showSubtypes) {
185382beadfa067b1e286fa604f8d7960d769411c954satok                mDialogBuilder.setPositiveButton(
185482beadfa067b1e286fa604f8d7960d769411c954satok                        com.android.internal.R.string.configure_input_methods,
18557f35c8cc88bea5230f001dd4356f864845d202e5satok                        new DialogInterface.OnClickListener() {
18567f35c8cc88bea5230f001dd4356f864845d202e5satok                            public void onClick(DialogInterface dialog, int whichButton) {
1857217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                                showConfigureInputMethods();
18587f35c8cc88bea5230f001dd4356f864845d202e5satok                            }
18597f35c8cc88bea5230f001dd4356f864845d202e5satok                        });
18607f35c8cc88bea5230f001dd4356f864845d202e5satok            }
18619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSwitchingDialog = mDialogBuilder.create();
18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSwitchingDialog.getWindow().setType(
18639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
18649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSwitchingDialog.show();
18659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1867ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
18689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void hideInputMethodMenu() {
1869105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        synchronized (mMethodMap) {
1870105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            hideInputMethodMenuLocked();
1871105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1872105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
1873ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1874105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    void hideInputMethodMenuLocked() {
18758a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        if (DEBUG) Slog.v(TAG, "Hide switching menu");
18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1877105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (mSwitchingDialog != null) {
1878105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mSwitchingDialog.dismiss();
1879105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mSwitchingDialog = null;
18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1881ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1882105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mDialogBuilder = null;
1883105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mItems = null;
1884105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mIms = null;
18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1886ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ----------------------------------------------------------------------
1888ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean setInputMethodEnabled(String id, boolean enabled) {
18909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
18919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mContext.checkCallingOrSelfPermission(
18929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    android.Manifest.permission.WRITE_SECURE_SETTINGS)
18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    != PackageManager.PERMISSION_GRANTED) {
18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new SecurityException(
18959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "Requires permission "
18969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + android.Manifest.permission.WRITE_SECURE_SETTINGS);
18979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
189821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
18999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long ident = Binder.clearCallingIdentity();
19009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
190121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                return setInputMethodEnabledLocked(id, enabled);
190221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            } finally {
190321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                Binder.restoreCallingIdentity(ident);
190421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            }
190521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        }
190621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    }
190721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
190821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    boolean setInputMethodEnabledLocked(String id, boolean enabled) {
190921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        // Make sure this is a valid input method.
191021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        InputMethodInfo imm = mMethodMap.get(id);
191121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        if (imm == null) {
1912d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
191321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        }
1914ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1915d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
1916d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                .getEnabledInputMethodsAndSubtypeListLocked();
1917ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1918d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        if (enabled) {
1919d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
1920d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                if (pair.first.equals(id)) {
1921d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // We are enabling this input method, but it is already enabled.
1922d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // Nothing to do. The previous state was enabled.
1923d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    return true;
19249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
192521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            }
1926d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mSettings.appendAndPutEnabledInputMethodLocked(id, false);
1927d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            // Previous state was disabled.
1928d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return false;
1929d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        } else {
1930d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            StringBuilder builder = new StringBuilder();
1931d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (mSettings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
1932d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    builder, enabledInputMethodsList, id)) {
1933d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Disabled input method is currently selected, switch to another one.
1934d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                String selId = Settings.Secure.getString(mContext.getContentResolver(),
1935d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                        Settings.Secure.DEFAULT_INPUT_METHOD);
193603eb319a3a7fe6fe9ab9eba6fc1f727285850906satok                if (id.equals(selId) && !chooseNewDefaultIMELocked()) {
193703eb319a3a7fe6fe9ab9eba6fc1f727285850906satok                    Slog.i(TAG, "Can't find new IME, unsetting the current input method.");
193803eb319a3a7fe6fe9ab9eba6fc1f727285850906satok                    resetSelectedInputMethodAndSubtypeLocked("");
1939d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
1940d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Previous state was enabled.
1941d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                return true;
1942d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            } else {
1943d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // We are disabling the input method but it is already disabled.
1944d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Nothing to do.  The previous state was disabled.
19459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
19469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19494df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project
195057ffc00239edcfe733832771e1429fca20182207satok    private boolean canAddToLastInputMethod(InputMethodSubtype subtype) {
195157ffc00239edcfe733832771e1429fca20182207satok        if (subtype == null) return true;
195257ffc00239edcfe733832771e1429fca20182207satok        String[] extraValues = subtype.getExtraValue().split(",");
195357ffc00239edcfe733832771e1429fca20182207satok        final int N = extraValues.length;
195457ffc00239edcfe733832771e1429fca20182207satok        for (int i = 0; i < N; ++i) {
195557ffc00239edcfe733832771e1429fca20182207satok            if (SUBTYPE_EXTRAVALUE_EXCLUDE_FROM_LAST_IME.equals(extraValues[i])) {
195657ffc00239edcfe733832771e1429fca20182207satok                return false;
195757ffc00239edcfe733832771e1429fca20182207satok            }
195857ffc00239edcfe733832771e1429fca20182207satok        }
195957ffc00239edcfe733832771e1429fca20182207satok        return true;
196057ffc00239edcfe733832771e1429fca20182207satok    }
196157ffc00239edcfe733832771e1429fca20182207satok
1962723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    private void saveCurrentInputMethodAndSubtypeToHistory() {
1963723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        String subtypeId = NOT_A_SUBTYPE_ID_STR;
1964723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        if (mCurrentSubtype != null) {
1965723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            subtypeId = String.valueOf(mCurrentSubtype.hashCode());
1966723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
196757ffc00239edcfe733832771e1429fca20182207satok        if (canAddToLastInputMethod(mCurrentSubtype)) {
196857ffc00239edcfe733832771e1429fca20182207satok            mSettings.addSubtypeToHistory(mCurMethodId, subtypeId);
196957ffc00239edcfe733832771e1429fca20182207satok        }
1970ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
1971ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
1972723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
1973723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            boolean setSubtypeOnly) {
19744d733290a112fbe7ca5631ee870094b538f39d80satok        mOldSystemSettingsVersion = getSystemSettingsVersion();
1975723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        // Update the history of InputMethod and Subtype
1976723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        saveCurrentInputMethodAndSubtypeToHistory();
1977723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
1978723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        // Set Subtype here
1979723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        if (imi == null || subtypeId < 0) {
1980723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
19810ba75bb22c2992f649ee5f7605a2b45442ad4862Tadashi G. Takaoka            mCurrentSubtype = null;
1982723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        } else {
1983586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa            if (subtypeId < imi.getSubtypeCount()) {
1984586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                InputMethodSubtype subtype = imi.getSubtypeAt(subtypeId);
1985586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                mSettings.putSelectedSubtype(subtype.hashCode());
1986586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                mCurrentSubtype = subtype;
1987723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            } else {
1988723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
1989723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                mCurrentSubtype = null;
1990723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
1991723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
1992723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
1993723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        if (!setSubtypeOnly) {
1994723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // Set InputMethod here
1995723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mSettings.putSelectedInputMethod(imi != null ? imi.getId() : "");
19961ab852fbcfe155c9d4373b7130f8515591669634satok        }
1997ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
1998ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
1999723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
2000723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        InputMethodInfo imi = mMethodMap.get(newDefaultIme);
2001723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        int lastSubtypeId = NOT_A_SUBTYPE_ID;
2002723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        // newDefaultIme is empty when there is no candidate for the selected IME.
2003723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        if (imi != null && !TextUtils.isEmpty(newDefaultIme)) {
2004723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            String subtypeHashCode = mSettings.getLastSubtypeForInputMethodLocked(newDefaultIme);
2005723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (subtypeHashCode != null) {
2006723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                try {
2007723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    lastSubtypeId = getSubtypeIdFromHashCode(
2008723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                            imi, Integer.valueOf(subtypeHashCode));
2009723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                } catch (NumberFormatException e) {
2010723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    Slog.w(TAG, "HashCode for subtype looks broken: " + subtypeHashCode, e);
2011723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
2012723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2013723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2014723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        setSelectedInputMethodAndSubtypeLocked(imi, lastSubtypeId, false);
2015723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    }
2016723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2017ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private int getSelectedInputMethodSubtypeId(String id) {
2018ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        InputMethodInfo imi = mMethodMap.get(id);
2019ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        if (imi == null) {
2020ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            return NOT_A_SUBTYPE_ID;
2021ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        }
2022ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        int subtypeId;
2023ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        try {
2024ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            subtypeId = Settings.Secure.getInt(mContext.getContentResolver(),
2025ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE);
2026ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        } catch (SettingNotFoundException e) {
2027ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            return NOT_A_SUBTYPE_ID;
2028ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        }
2029723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        return getSubtypeIdFromHashCode(imi, subtypeId);
2030723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    }
2031723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2032723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    private int getSubtypeIdFromHashCode(InputMethodInfo imi, int subtypeHashCode) {
20332820351489537698ad153c6397edf3270455edc5satok        if (imi != null) {
2034586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa            final int subtypeCount = imi.getSubtypeCount();
2035586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa            for (int i = 0; i < subtypeCount; ++i) {
2036586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                InputMethodSubtype ims = imi.getSubtypeAt(i);
20372820351489537698ad153c6397edf3270455edc5satok                if (subtypeHashCode == ims.hashCode()) {
20382820351489537698ad153c6397edf3270455edc5satok                    return i;
20392820351489537698ad153c6397edf3270455edc5satok                }
2040ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            }
2041ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        }
2042ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        return NOT_A_SUBTYPE_ID;
2043ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
2044ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2045df31ae6a3011d47421a6ac10021f9649dc34a156satok    private static ArrayList<InputMethodSubtype> getApplicableSubtypesLocked(
2046df31ae6a3011d47421a6ac10021f9649dc34a156satok            Resources res, List<InputMethodSubtype> subtypes) {
2047df31ae6a3011d47421a6ac10021f9649dc34a156satok        final String systemLocale = res.getConfiguration().locale.toString();
20483da922367c0dbe67b97fe97fcfca13fd93602f7asatok        if (TextUtils.isEmpty(systemLocale)) return new ArrayList<InputMethodSubtype>();
20493da922367c0dbe67b97fe97fcfca13fd93602f7asatok        HashMap<String, InputMethodSubtype> applicableModeAndSubtypesMap =
20503da922367c0dbe67b97fe97fcfca13fd93602f7asatok                new HashMap<String, InputMethodSubtype>();
205116331c8a1d33defccc5cbb18694def79196c921bsatok        final int N = subtypes.size();
205216331c8a1d33defccc5cbb18694def79196c921bsatok        boolean containsKeyboardSubtype = false;
205316331c8a1d33defccc5cbb18694def79196c921bsatok        for (int i = 0; i < N; ++i) {
205416331c8a1d33defccc5cbb18694def79196c921bsatok            InputMethodSubtype subtype = subtypes.get(i);
20553da922367c0dbe67b97fe97fcfca13fd93602f7asatok            final String locale = subtype.getLocale();
20563da922367c0dbe67b97fe97fcfca13fd93602f7asatok            final String mode = subtype.getMode();
20573da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // When system locale starts with subtype's locale, that subtype will be applicable
20583da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // for system locale
20593da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // For instance, it's clearly applicable for cases like system locale = en_US and
20603da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // subtype = en, but it is not necessarily considered applicable for cases like system
20613da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // locale = en and subtype = en_US.
20623da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // We just call systemLocale.startsWith(locale) in this function because there is no
20633da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // need to find applicable subtypes aggressively unlike
20643da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // findLastResortApplicableSubtypeLocked.
20653da922367c0dbe67b97fe97fcfca13fd93602f7asatok            if (systemLocale.startsWith(locale)) {
20663da922367c0dbe67b97fe97fcfca13fd93602f7asatok                InputMethodSubtype applicableSubtype = applicableModeAndSubtypesMap.get(mode);
20673da922367c0dbe67b97fe97fcfca13fd93602f7asatok                // If more applicable subtypes are contained, skip.
20683da922367c0dbe67b97fe97fcfca13fd93602f7asatok                if (applicableSubtype != null
20693da922367c0dbe67b97fe97fcfca13fd93602f7asatok                        && systemLocale.equals(applicableSubtype.getLocale())) continue;
20703da922367c0dbe67b97fe97fcfca13fd93602f7asatok                applicableModeAndSubtypesMap.put(mode, subtype);
207116331c8a1d33defccc5cbb18694def79196c921bsatok                if (!containsKeyboardSubtype
207216331c8a1d33defccc5cbb18694def79196c921bsatok                        && SUBTYPE_MODE_KEYBOARD.equalsIgnoreCase(subtype.getMode())) {
207316331c8a1d33defccc5cbb18694def79196c921bsatok                    containsKeyboardSubtype = true;
207416331c8a1d33defccc5cbb18694def79196c921bsatok                }
207516331c8a1d33defccc5cbb18694def79196c921bsatok            }
207616331c8a1d33defccc5cbb18694def79196c921bsatok        }
20773da922367c0dbe67b97fe97fcfca13fd93602f7asatok        ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<InputMethodSubtype>(
20783da922367c0dbe67b97fe97fcfca13fd93602f7asatok                applicableModeAndSubtypesMap.values());
207916331c8a1d33defccc5cbb18694def79196c921bsatok        if (!containsKeyboardSubtype) {
208016331c8a1d33defccc5cbb18694def79196c921bsatok            InputMethodSubtype lastResortKeyboardSubtype = findLastResortApplicableSubtypeLocked(
2081df31ae6a3011d47421a6ac10021f9649dc34a156satok                    res, subtypes, SUBTYPE_MODE_KEYBOARD, systemLocale, true);
208216331c8a1d33defccc5cbb18694def79196c921bsatok            if (lastResortKeyboardSubtype != null) {
208316331c8a1d33defccc5cbb18694def79196c921bsatok                applicableSubtypes.add(lastResortKeyboardSubtype);
208416331c8a1d33defccc5cbb18694def79196c921bsatok            }
208516331c8a1d33defccc5cbb18694def79196c921bsatok        }
208616331c8a1d33defccc5cbb18694def79196c921bsatok        return applicableSubtypes;
208716331c8a1d33defccc5cbb18694def79196c921bsatok    }
208816331c8a1d33defccc5cbb18694def79196c921bsatok
20894e4569dab5c75804b01a19b2d6e6101b445c1c68satok    /**
20904e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * If there are no selected subtypes, tries finding the most applicable one according to the
20914e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * given locale.
20924e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * @param subtypes this function will search the most applicable subtype in subtypes
20934e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * @param mode subtypes will be filtered by mode
20944e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * @param locale subtypes will be filtered by locale
20957599a7fb1ab5b75ca801f7d7e448f4c097320e01satok     * @param canIgnoreLocaleAsLastResort if this function can't find the most applicable subtype,
20967599a7fb1ab5b75ca801f7d7e448f4c097320e01satok     * it will return the first subtype matched with mode
20974e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * @return the most applicable subtypeId
20984e4569dab5c75804b01a19b2d6e6101b445c1c68satok     */
2099df31ae6a3011d47421a6ac10021f9649dc34a156satok    private static InputMethodSubtype findLastResortApplicableSubtypeLocked(
2100df31ae6a3011d47421a6ac10021f9649dc34a156satok            Resources res, List<InputMethodSubtype> subtypes, String mode, String locale,
21017599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            boolean canIgnoreLocaleAsLastResort) {
21028fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        if (subtypes == null || subtypes.size() == 0) {
2103cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            return null;
21048fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        }
21054e4569dab5c75804b01a19b2d6e6101b445c1c68satok        if (TextUtils.isEmpty(locale)) {
2106df31ae6a3011d47421a6ac10021f9649dc34a156satok            locale = res.getConfiguration().locale.toString();
21074e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
21088fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        final String language = locale.substring(0, 2);
21098fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        boolean partialMatchFound = false;
2110cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok        InputMethodSubtype applicableSubtype = null;
21117599a7fb1ab5b75ca801f7d7e448f4c097320e01satok        InputMethodSubtype firstMatchedModeSubtype = null;
211216331c8a1d33defccc5cbb18694def79196c921bsatok        final int N = subtypes.size();
211316331c8a1d33defccc5cbb18694def79196c921bsatok        for (int i = 0; i < N; ++i) {
2114cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            InputMethodSubtype subtype = subtypes.get(i);
2115cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            final String subtypeLocale = subtype.getLocale();
2116d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok            // An applicable subtype should match "mode". If mode is null, mode will be ignored,
2117d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok            // and all subtypes with all modes can be candidates.
2118d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok            if (mode == null || subtypes.get(i).getMode().equalsIgnoreCase(mode)) {
21197599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                if (firstMatchedModeSubtype == null) {
21207599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                    firstMatchedModeSubtype = subtype;
21217599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                }
21229ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                if (locale.equals(subtypeLocale)) {
21239ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                    // Exact match (e.g. system locale is "en_US" and subtype locale is "en_US")
2124cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    applicableSubtype = subtype;
21259ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                    break;
21269ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                } else if (!partialMatchFound && subtypeLocale.startsWith(language)) {
21279ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                    // Partial match (e.g. system locale is "en_US" and subtype locale is "en")
2128cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    applicableSubtype = subtype;
21299ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                    partialMatchFound = true;
21309ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                }
21318fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok            }
21328fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        }
21338fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok
21347599a7fb1ab5b75ca801f7d7e448f4c097320e01satok        if (applicableSubtype == null && canIgnoreLocaleAsLastResort) {
21357599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            return firstMatchedModeSubtype;
213616331c8a1d33defccc5cbb18694def79196c921bsatok        }
213716331c8a1d33defccc5cbb18694def79196c921bsatok
21388fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        // The first subtype applicable to the system locale will be defined as the most applicable
21398fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        // subtype.
21408fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        if (DEBUG) {
214116331c8a1d33defccc5cbb18694def79196c921bsatok            if (applicableSubtype != null) {
214216331c8a1d33defccc5cbb18694def79196c921bsatok                Slog.d(TAG, "Applicable InputMethodSubtype was found: "
214316331c8a1d33defccc5cbb18694def79196c921bsatok                        + applicableSubtype.getMode() + "," + applicableSubtype.getLocale());
214416331c8a1d33defccc5cbb18694def79196c921bsatok            }
21458fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        }
2146cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok        return applicableSubtype;
21478fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok    }
21488fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok
21494e4569dab5c75804b01a19b2d6e6101b445c1c68satok    // If there are no selected shortcuts, tries finding the most applicable ones.
21504e4569dab5c75804b01a19b2d6e6101b445c1c68satok    private Pair<InputMethodInfo, InputMethodSubtype>
21514e4569dab5c75804b01a19b2d6e6101b445c1c68satok            findLastResortApplicableShortcutInputMethodAndSubtypeLocked(String mode) {
21524e4569dab5c75804b01a19b2d6e6101b445c1c68satok        List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
21534e4569dab5c75804b01a19b2d6e6101b445c1c68satok        InputMethodInfo mostApplicableIMI = null;
2154cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok        InputMethodSubtype mostApplicableSubtype = null;
21554e4569dab5c75804b01a19b2d6e6101b445c1c68satok        boolean foundInSystemIME = false;
21564e4569dab5c75804b01a19b2d6e6101b445c1c68satok
21574e4569dab5c75804b01a19b2d6e6101b445c1c68satok        // Search applicable subtype for each InputMethodInfo
21584e4569dab5c75804b01a19b2d6e6101b445c1c68satok        for (InputMethodInfo imi: imis) {
21597599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            final String imiId = imi.getId();
21607599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            if (foundInSystemIME && !imiId.equals(mCurMethodId)) {
21617599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                continue;
21627599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            }
2163cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            InputMethodSubtype subtype = null;
2164df31ae6a3011d47421a6ac10021f9649dc34a156satok            final List<InputMethodSubtype> enabledSubtypes =
2165df31ae6a3011d47421a6ac10021f9649dc34a156satok                    getEnabledInputMethodSubtypeList(imi, true);
2166df31ae6a3011d47421a6ac10021f9649dc34a156satok            // 1. Search by the current subtype's locale from enabledSubtypes.
21674e4569dab5c75804b01a19b2d6e6101b445c1c68satok            if (mCurrentSubtype != null) {
2168cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                subtype = findLastResortApplicableSubtypeLocked(
2169df31ae6a3011d47421a6ac10021f9649dc34a156satok                        mRes, enabledSubtypes, mode, mCurrentSubtype.getLocale(), false);
21704e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
2171df31ae6a3011d47421a6ac10021f9649dc34a156satok            // 2. Search by the system locale from enabledSubtypes.
2172df31ae6a3011d47421a6ac10021f9649dc34a156satok            // 3. Search the first enabled subtype matched with mode from enabledSubtypes.
2173cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            if (subtype == null) {
2174cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                subtype = findLastResortApplicableSubtypeLocked(
2175df31ae6a3011d47421a6ac10021f9649dc34a156satok                        mRes, enabledSubtypes, mode, null, true);
21767599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            }
21777599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            // 4. Search by the current subtype's locale from all subtypes.
21787599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            if (subtype == null && mCurrentSubtype != null) {
21797599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                subtype = findLastResortApplicableSubtypeLocked(
2180586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                        mRes, getSubtypes(imi), mode, mCurrentSubtype.getLocale(), false);
21814e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
21827599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            // 5. Search by the system locale from all subtypes.
21837599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            // 6. Search the first enabled subtype matched with mode from all subtypes.
2184cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            if (subtype == null) {
21857599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                subtype = findLastResortApplicableSubtypeLocked(
2186586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                        mRes, getSubtypes(imi), mode, null, true);
21874e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
2188cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            if (subtype != null) {
21897599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                if (imiId.equals(mCurMethodId)) {
21904e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    // The current input method is the most applicable IME.
21914e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    mostApplicableIMI = imi;
2192cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    mostApplicableSubtype = subtype;
21934e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    break;
21944e4569dab5c75804b01a19b2d6e6101b445c1c68satok                } else if (!foundInSystemIME) {
21957599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                    // The system input method is 2nd applicable IME.
21964e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    mostApplicableIMI = imi;
2197cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    mostApplicableSubtype = subtype;
21987599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                    if ((imi.getServiceInfo().applicationInfo.flags
21997599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                            & ApplicationInfo.FLAG_SYSTEM) != 0) {
22007599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                        foundInSystemIME = true;
22017599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                    }
22024e4569dab5c75804b01a19b2d6e6101b445c1c68satok                }
22034e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
22044e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
22054e4569dab5c75804b01a19b2d6e6101b445c1c68satok        if (DEBUG) {
2206cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            if (mostApplicableIMI != null) {
2207cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                Slog.w(TAG, "Most applicable shortcut input method was:"
2208cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                        + mostApplicableIMI.getId());
2209cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                if (mostApplicableSubtype != null) {
2210cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    Slog.w(TAG, "Most applicable shortcut input method subtype was:"
2211cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                            + "," + mostApplicableSubtype.getMode() + ","
2212cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                            + mostApplicableSubtype.getLocale());
2213cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                }
2214cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            }
22154e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
2216cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok        if (mostApplicableIMI != null) {
22174e4569dab5c75804b01a19b2d6e6101b445c1c68satok            return new Pair<InputMethodInfo, InputMethodSubtype> (mostApplicableIMI,
2218cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    mostApplicableSubtype);
22194e4569dab5c75804b01a19b2d6e6101b445c1c68satok        } else {
22204e4569dab5c75804b01a19b2d6e6101b445c1c68satok            return null;
22214e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
22224e4569dab5c75804b01a19b2d6e6101b445c1c68satok    }
22234e4569dab5c75804b01a19b2d6e6101b445c1c68satok
22244d733290a112fbe7ca5631ee870094b538f39d80satok    private static long getSystemSettingsVersion() {
22254d733290a112fbe7ca5631ee870094b538f39d80satok        return SystemProperties.getLong(Settings.Secure.SYS_PROP_SETTING_VERSION, 0);
22264d733290a112fbe7ca5631ee870094b538f39d80satok    }
22274d733290a112fbe7ca5631ee870094b538f39d80satok
2228ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    /**
2229ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * @return Return the current subtype of this input method.
2230ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     */
2231ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    public InputMethodSubtype getCurrentInputMethodSubtype() {
22324e4569dab5c75804b01a19b2d6e6101b445c1c68satok        boolean subtypeIsSelected = false;
22334e4569dab5c75804b01a19b2d6e6101b445c1c68satok        try {
22344e4569dab5c75804b01a19b2d6e6101b445c1c68satok            subtypeIsSelected = Settings.Secure.getInt(mContext.getContentResolver(),
22354e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE) != NOT_A_SUBTYPE_ID;
22364e4569dab5c75804b01a19b2d6e6101b445c1c68satok        } catch (SettingNotFoundException e) {
22374e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
22383ef8b29fa03fe3ae1c57fd891a12afa46128fff8satok        synchronized (mMethodMap) {
22393ef8b29fa03fe3ae1c57fd891a12afa46128fff8satok            if (!subtypeIsSelected || mCurrentSubtype == null) {
22404e4569dab5c75804b01a19b2d6e6101b445c1c68satok                String lastInputMethodId = Settings.Secure.getString(
22414e4569dab5c75804b01a19b2d6e6101b445c1c68satok                        mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
22423ef8b29fa03fe3ae1c57fd891a12afa46128fff8satok                int subtypeId = getSelectedInputMethodSubtypeId(lastInputMethodId);
22433ef8b29fa03fe3ae1c57fd891a12afa46128fff8satok                if (subtypeId == NOT_A_SUBTYPE_ID) {
22444e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    InputMethodInfo imi = mMethodMap.get(lastInputMethodId);
22454e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    if (imi != null) {
22464e4569dab5c75804b01a19b2d6e6101b445c1c68satok                        // If there are no selected subtypes, the framework will try to find
2247d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                        // the most applicable subtype from explicitly or implicitly enabled
2248d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                        // subtypes.
2249d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                        List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
2250d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                                getEnabledInputMethodSubtypeList(imi, true);
2251d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                        // If there is only one explicitly or implicitly enabled subtype,
2252d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                        // just returns it.
2253d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                        if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
2254d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                            mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
2255d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                        } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
2256d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                            mCurrentSubtype = findLastResortApplicableSubtypeLocked(
2257d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                                    mRes, explicitlyOrImplicitlyEnabledSubtypes,
2258d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                                    SUBTYPE_MODE_KEYBOARD, null, true);
2259d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                            if (mCurrentSubtype == null) {
2260d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                                mCurrentSubtype = findLastResortApplicableSubtypeLocked(
2261d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                                        mRes, explicitlyOrImplicitlyEnabledSubtypes, null, null,
2262d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                                        true);
2263d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                            }
2264d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok                        }
22654e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    }
2266cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                } else {
22673ef8b29fa03fe3ae1c57fd891a12afa46128fff8satok                    mCurrentSubtype =
2268586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                            getSubtypes(mMethodMap.get(lastInputMethodId)).get(subtypeId);
22693ef8b29fa03fe3ae1c57fd891a12afa46128fff8satok                }
22708fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok            }
22713ef8b29fa03fe3ae1c57fd891a12afa46128fff8satok            return mCurrentSubtype;
22728fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        }
2273ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
2274ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2275f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok    private void addShortcutInputMethodAndSubtypes(InputMethodInfo imi,
2276f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            InputMethodSubtype subtype) {
2277f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok        if (mShortcutInputMethodsAndSubtypes.containsKey(imi)) {
2278f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            mShortcutInputMethodsAndSubtypes.get(imi).add(subtype);
2279f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok        } else {
2280f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
2281f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            subtypes.add(subtype);
2282f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            mShortcutInputMethodsAndSubtypes.put(imi, subtypes);
2283f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok        }
2284f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok    }
2285f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok
22864e4569dab5c75804b01a19b2d6e6101b445c1c68satok    // TODO: We should change the return type from List to List<Parcelable>
22874e4569dab5c75804b01a19b2d6e6101b445c1c68satok    public List getShortcutInputMethodsAndSubtypes() {
22884e4569dab5c75804b01a19b2d6e6101b445c1c68satok        synchronized (mMethodMap) {
22893da922367c0dbe67b97fe97fcfca13fd93602f7asatok            ArrayList<Object> ret = new ArrayList<Object>();
2290f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            if (mShortcutInputMethodsAndSubtypes.size() == 0) {
22914e4569dab5c75804b01a19b2d6e6101b445c1c68satok                // If there are no selected shortcut subtypes, the framework will try to find
22924e4569dab5c75804b01a19b2d6e6101b445c1c68satok                // the most applicable subtype from all subtypes whose mode is
22934e4569dab5c75804b01a19b2d6e6101b445c1c68satok                // SUBTYPE_MODE_VOICE. This is an exceptional case, so we will hardcode the mode.
2294f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                Pair<InputMethodInfo, InputMethodSubtype> info =
2295f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                    findLastResortApplicableShortcutInputMethodAndSubtypeLocked(
2296f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                            SUBTYPE_MODE_VOICE);
22977599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                if (info != null) {
22983da922367c0dbe67b97fe97fcfca13fd93602f7asatok                    ret.add(info.first);
22993da922367c0dbe67b97fe97fcfca13fd93602f7asatok                    ret.add(info.second);
23007599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                }
23013da922367c0dbe67b97fe97fcfca13fd93602f7asatok                return ret;
2302f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            }
2303f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            for (InputMethodInfo imi: mShortcutInputMethodsAndSubtypes.keySet()) {
2304f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                ret.add(imi);
2305f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                for (InputMethodSubtype subtype: mShortcutInputMethodsAndSubtypes.get(imi)) {
2306f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                    ret.add(subtype);
23074e4569dab5c75804b01a19b2d6e6101b445c1c68satok                }
23084e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
2309f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            return ret;
23104e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
23114e4569dab5c75804b01a19b2d6e6101b445c1c68satok    }
23124e4569dab5c75804b01a19b2d6e6101b445c1c68satok
2313b66d287e3003a0934d5714fbf15e554b3c814906satok    public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
2314b66d287e3003a0934d5714fbf15e554b3c814906satok        synchronized (mMethodMap) {
2315b66d287e3003a0934d5714fbf15e554b3c814906satok            if (subtype != null && mCurMethodId != null) {
2316b66d287e3003a0934d5714fbf15e554b3c814906satok                InputMethodInfo imi = mMethodMap.get(mCurMethodId);
2317b66d287e3003a0934d5714fbf15e554b3c814906satok                int subtypeId = getSubtypeIdFromHashCode(imi, subtype.hashCode());
2318b66d287e3003a0934d5714fbf15e554b3c814906satok                if (subtypeId != NOT_A_SUBTYPE_ID) {
2319b66d287e3003a0934d5714fbf15e554b3c814906satok                    setInputMethodLocked(mCurMethodId, subtypeId);
2320b66d287e3003a0934d5714fbf15e554b3c814906satok                    return true;
2321b66d287e3003a0934d5714fbf15e554b3c814906satok                }
2322b66d287e3003a0934d5714fbf15e554b3c814906satok            }
2323b66d287e3003a0934d5714fbf15e554b3c814906satok            return false;
2324b66d287e3003a0934d5714fbf15e554b3c814906satok        }
2325b66d287e3003a0934d5714fbf15e554b3c814906satok    }
2326b66d287e3003a0934d5714fbf15e554b3c814906satok
2327d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    /**
2328d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok     * Utility class for putting and getting settings for InputMethod
2329d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok     * TODO: Move all putters and getters of settings to this class.
2330d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok     */
2331d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    private static class InputMethodSettings {
2332d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // The string for enabled input method is saved as follows:
2333d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // example: ("ime0;subtype0;subtype1;subtype2:ime1:ime2;subtype0")
2334d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private static final char INPUT_METHOD_SEPARATER = ':';
2335d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private static final char INPUT_METHOD_SUBTYPE_SEPARATER = ';';
2336723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private final TextUtils.SimpleStringSplitter mInputMethodSplitter =
2337d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATER);
2338d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
2339723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private final TextUtils.SimpleStringSplitter mSubtypeSplitter =
2340d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATER);
2341d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
2342df31ae6a3011d47421a6ac10021f9649dc34a156satok        private final Resources mRes;
2343d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private final ContentResolver mResolver;
2344d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private final HashMap<String, InputMethodInfo> mMethodMap;
2345d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private final ArrayList<InputMethodInfo> mMethodList;
2346d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
2347d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private String mEnabledInputMethodsStrCache;
2348d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
2349d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private static void buildEnabledInputMethodsSettingString(
2350d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                StringBuilder builder, Pair<String, ArrayList<String>> pair) {
2351d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            String id = pair.first;
2352d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            ArrayList<String> subtypes = pair.second;
2353d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            builder.append(id);
235457c767c7b7a4cdcd0c33ec453a9f2c0b853999b6satok            // Inputmethod and subtypes are saved in the settings as follows:
235557c767c7b7a4cdcd0c33ec453a9f2c0b853999b6satok            // ime0;subtype0;subtype1:ime1;subtype0:ime2:ime3;subtype0;subtype1
235657c767c7b7a4cdcd0c33ec453a9f2c0b853999b6satok            for (String subtypeId: subtypes) {
235757c767c7b7a4cdcd0c33ec453a9f2c0b853999b6satok                builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypeId);
2358d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
2359d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
2360d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
2361d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public InputMethodSettings(
2362df31ae6a3011d47421a6ac10021f9649dc34a156satok                Resources res, ContentResolver resolver,
2363df31ae6a3011d47421a6ac10021f9649dc34a156satok                HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList) {
2364df31ae6a3011d47421a6ac10021f9649dc34a156satok            mRes = res;
2365d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mResolver = resolver;
2366d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mMethodMap = methodMap;
2367d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mMethodList = methodList;
2368d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
2369d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
2370d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public List<InputMethodInfo> getEnabledInputMethodListLocked() {
2371d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return createEnabledInputMethodListLocked(
2372d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    getEnabledInputMethodsAndSubtypeListLocked());
2373d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
2374d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
23757f35c8cc88bea5230f001dd4356f864845d202e5satok        public List<Pair<InputMethodInfo, ArrayList<String>>>
237667ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                getEnabledInputMethodAndSubtypeHashCodeListLocked() {
237767ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            return createEnabledInputMethodAndSubtypeHashCodeListLocked(
23787f35c8cc88bea5230f001dd4356f864845d202e5satok                    getEnabledInputMethodsAndSubtypeListLocked());
23797f35c8cc88bea5230f001dd4356f864845d202e5satok        }
23807f35c8cc88bea5230f001dd4356f864845d202e5satok
238167ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok        public List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(
238267ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                InputMethodInfo imi) {
238367ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            List<Pair<String, ArrayList<String>>> imsList =
238467ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                    getEnabledInputMethodsAndSubtypeListLocked();
238567ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            ArrayList<InputMethodSubtype> enabledSubtypes =
238667ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                    new ArrayList<InputMethodSubtype>();
2387884ef9a11fb25b80630265daee46c5609707751fsatok            if (imi != null) {
2388884ef9a11fb25b80630265daee46c5609707751fsatok                for (Pair<String, ArrayList<String>> imsPair : imsList) {
2389884ef9a11fb25b80630265daee46c5609707751fsatok                    InputMethodInfo info = mMethodMap.get(imsPair.first);
2390884ef9a11fb25b80630265daee46c5609707751fsatok                    if (info != null && info.getId().equals(imi.getId())) {
2391586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                        final int subtypeCount = info.getSubtypeCount();
2392586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                        for (int i = 0; i < subtypeCount; ++i) {
2393586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                            InputMethodSubtype ims = info.getSubtypeAt(i);
2394884ef9a11fb25b80630265daee46c5609707751fsatok                            for (String s: imsPair.second) {
2395884ef9a11fb25b80630265daee46c5609707751fsatok                                if (String.valueOf(ims.hashCode()).equals(s)) {
2396884ef9a11fb25b80630265daee46c5609707751fsatok                                    enabledSubtypes.add(ims);
2397884ef9a11fb25b80630265daee46c5609707751fsatok                                }
239867ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                            }
239967ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                        }
2400884ef9a11fb25b80630265daee46c5609707751fsatok                        break;
240167ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                    }
240267ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                }
240367ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            }
240467ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            return enabledSubtypes;
240567ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok        }
240667ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok
2407d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // At the initial boot, the settings for input methods are not set,
2408d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // so we need to enable IME in that case.
2409d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public void enableAllIMEsIfThereIsNoEnabledIME() {
2410d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (TextUtils.isEmpty(getEnabledInputMethodsStr())) {
2411d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                StringBuilder sb = new StringBuilder();
2412d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                final int N = mMethodList.size();
2413d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                for (int i = 0; i < N; i++) {
2414d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    InputMethodInfo imi = mMethodList.get(i);
2415d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    Slog.i(TAG, "Adding: " + imi.getId());
2416d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    if (i > 0) sb.append(':');
2417d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    sb.append(imi.getId());
2418d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
2419d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                putEnabledInputMethodsStr(sb.toString());
2420d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
2421d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
2422d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
2423bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        private List<Pair<String, ArrayList<String>>> getEnabledInputMethodsAndSubtypeListLocked() {
2424d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            ArrayList<Pair<String, ArrayList<String>>> imsList
2425d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    = new ArrayList<Pair<String, ArrayList<String>>>();
2426d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            final String enabledInputMethodsStr = getEnabledInputMethodsStr();
2427d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (TextUtils.isEmpty(enabledInputMethodsStr)) {
2428d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                return imsList;
2429d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
2430723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mInputMethodSplitter.setString(enabledInputMethodsStr);
2431723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            while (mInputMethodSplitter.hasNext()) {
2432723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                String nextImsStr = mInputMethodSplitter.next();
2433723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                mSubtypeSplitter.setString(nextImsStr);
2434723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (mSubtypeSplitter.hasNext()) {
2435d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    ArrayList<String> subtypeHashes = new ArrayList<String>();
2436d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // The first element is ime id.
2437723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    String imeId = mSubtypeSplitter.next();
2438723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    while (mSubtypeSplitter.hasNext()) {
2439723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        subtypeHashes.add(mSubtypeSplitter.next());
2440d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    }
2441d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    imsList.add(new Pair<String, ArrayList<String>>(imeId, subtypeHashes));
2442d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
2443d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
2444d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return imsList;
2445d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
2446d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
2447d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public void appendAndPutEnabledInputMethodLocked(String id, boolean reloadInputMethodStr) {
2448d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (reloadInputMethodStr) {
2449d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                getEnabledInputMethodsStr();
2450d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
2451d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (TextUtils.isEmpty(mEnabledInputMethodsStrCache)) {
2452d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Add in the newly enabled input method.
2453d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                putEnabledInputMethodsStr(id);
2454d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            } else {
2455d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                putEnabledInputMethodsStr(
2456d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                        mEnabledInputMethodsStrCache + INPUT_METHOD_SEPARATER + id);
2457d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
2458d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
2459d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
2460d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        /**
2461d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok         * Build and put a string of EnabledInputMethods with removing specified Id.
2462d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok         * @return the specified id was removed or not.
2463d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok         */
2464d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public boolean buildAndPutEnabledInputMethodsStrRemovingIdLocked(
2465d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                StringBuilder builder, List<Pair<String, ArrayList<String>>> imsList, String id) {
2466d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            boolean isRemoved = false;
2467d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            boolean needsAppendSeparator = false;
2468d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            for (Pair<String, ArrayList<String>> ims: imsList) {
2469d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                String curId = ims.first;
2470d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                if (curId.equals(id)) {
2471d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // We are disabling this input method, and it is
2472d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // currently enabled.  Skip it to remove from the
2473d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // new list.
2474d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    isRemoved = true;
2475d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                } else {
2476d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    if (needsAppendSeparator) {
2477d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                        builder.append(INPUT_METHOD_SEPARATER);
2478d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    } else {
2479d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                        needsAppendSeparator = true;
2480d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    }
2481d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    buildEnabledInputMethodsSettingString(builder, ims);
2482d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
2483d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
2484d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (isRemoved) {
2485d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Update the setting with the new list of input methods.
2486d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                putEnabledInputMethodsStr(builder.toString());
2487d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
2488d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return isRemoved;
2489d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
2490d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
2491d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private List<InputMethodInfo> createEnabledInputMethodListLocked(
2492d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                List<Pair<String, ArrayList<String>>> imsList) {
2493d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            final ArrayList<InputMethodInfo> res = new ArrayList<InputMethodInfo>();
2494d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            for (Pair<String, ArrayList<String>> ims: imsList) {
2495d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                InputMethodInfo info = mMethodMap.get(ims.first);
2496d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                if (info != null) {
2497d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    res.add(info);
2498d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
2499d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
2500d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return res;
2501d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
2502d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
25037f35c8cc88bea5230f001dd4356f864845d202e5satok        private List<Pair<InputMethodInfo, ArrayList<String>>>
250467ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                createEnabledInputMethodAndSubtypeHashCodeListLocked(
25057f35c8cc88bea5230f001dd4356f864845d202e5satok                        List<Pair<String, ArrayList<String>>> imsList) {
25067f35c8cc88bea5230f001dd4356f864845d202e5satok            final ArrayList<Pair<InputMethodInfo, ArrayList<String>>> res
25077f35c8cc88bea5230f001dd4356f864845d202e5satok                    = new ArrayList<Pair<InputMethodInfo, ArrayList<String>>>();
25087f35c8cc88bea5230f001dd4356f864845d202e5satok            for (Pair<String, ArrayList<String>> ims : imsList) {
25097f35c8cc88bea5230f001dd4356f864845d202e5satok                InputMethodInfo info = mMethodMap.get(ims.first);
25107f35c8cc88bea5230f001dd4356f864845d202e5satok                if (info != null) {
25117f35c8cc88bea5230f001dd4356f864845d202e5satok                    res.add(new Pair<InputMethodInfo, ArrayList<String>>(info, ims.second));
25127f35c8cc88bea5230f001dd4356f864845d202e5satok                }
25137f35c8cc88bea5230f001dd4356f864845d202e5satok            }
25147f35c8cc88bea5230f001dd4356f864845d202e5satok            return res;
25157f35c8cc88bea5230f001dd4356f864845d202e5satok        }
25167f35c8cc88bea5230f001dd4356f864845d202e5satok
2517d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private void putEnabledInputMethodsStr(String str) {
2518d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            Settings.Secure.putString(mResolver, Settings.Secure.ENABLED_INPUT_METHODS, str);
2519d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mEnabledInputMethodsStrCache = str;
2520d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
2521d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
2522d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private String getEnabledInputMethodsStr() {
2523d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mEnabledInputMethodsStrCache = Settings.Secure.getString(
2524d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    mResolver, Settings.Secure.ENABLED_INPUT_METHODS);
2525723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (DEBUG) {
2526723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                Slog.d(TAG, "getEnabledInputMethodsStr: " + mEnabledInputMethodsStrCache);
2527723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2528d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return mEnabledInputMethodsStrCache;
2529d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
2530723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2531723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private void saveSubtypeHistory(
2532723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                List<Pair<String, String>> savedImes, String newImeId, String newSubtypeId) {
2533723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            StringBuilder builder = new StringBuilder();
2534723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            boolean isImeAdded = false;
2535723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (!TextUtils.isEmpty(newImeId) && !TextUtils.isEmpty(newSubtypeId)) {
2536723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                builder.append(newImeId).append(INPUT_METHOD_SUBTYPE_SEPARATER).append(
2537723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        newSubtypeId);
2538723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                isImeAdded = true;
2539723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2540723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            for (Pair<String, String> ime: savedImes) {
2541723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                String imeId = ime.first;
2542723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                String subtypeId = ime.second;
2543723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (TextUtils.isEmpty(subtypeId)) {
2544723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    subtypeId = NOT_A_SUBTYPE_ID_STR;
2545723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
2546723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (isImeAdded) {
2547723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    builder.append(INPUT_METHOD_SEPARATER);
2548723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                } else {
2549723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    isImeAdded = true;
2550723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
2551723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                builder.append(imeId).append(INPUT_METHOD_SUBTYPE_SEPARATER).append(
2552723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        subtypeId);
2553723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2554723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // Remove the last INPUT_METHOD_SEPARATER
2555723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            putSubtypeHistoryStr(builder.toString());
2556723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2557723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2558723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public void addSubtypeToHistory(String imeId, String subtypeId) {
2559723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            List<Pair<String, String>> subtypeHistory = loadInputMethodAndSubtypeHistoryLocked();
2560723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            for (Pair<String, String> ime: subtypeHistory) {
2561723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (ime.first.equals(imeId)) {
2562723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    if (DEBUG) {
2563bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                        Slog.v(TAG, "Subtype found in the history: " + imeId + ", "
2564723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                                + ime.second);
2565723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    }
2566723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    // We should break here
2567723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    subtypeHistory.remove(ime);
2568723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    break;
2569723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
2570723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2571bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            if (DEBUG) {
2572bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                Slog.v(TAG, "Add subtype to the history: " + imeId + ", " + subtypeId);
2573bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            }
2574723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            saveSubtypeHistory(subtypeHistory, imeId, subtypeId);
2575723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2576723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2577723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private void putSubtypeHistoryStr(String str) {
2578723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (DEBUG) {
2579723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                Slog.d(TAG, "putSubtypeHistoryStr: " + str);
2580723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2581723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            Settings.Secure.putString(
2582723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, str);
2583723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2584723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2585723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public Pair<String, String> getLastInputMethodAndSubtypeLocked() {
2586723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // Gets the first one from the history
2587723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            return getLastSubtypeForInputMethodLockedInternal(null);
2588723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2589723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2590723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public String getLastSubtypeForInputMethodLocked(String imeId) {
2591723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            Pair<String, String> ime = getLastSubtypeForInputMethodLockedInternal(imeId);
2592723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (ime != null) {
2593723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                return ime.second;
2594723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            } else {
2595723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                return null;
2596723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2597723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2598723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2599723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private Pair<String, String> getLastSubtypeForInputMethodLockedInternal(String imeId) {
2600723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            List<Pair<String, ArrayList<String>>> enabledImes =
2601723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    getEnabledInputMethodsAndSubtypeListLocked();
2602723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            List<Pair<String, String>> subtypeHistory = loadInputMethodAndSubtypeHistoryLocked();
2603723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            for (Pair<String, String> imeAndSubtype: subtypeHistory) {
2604723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                final String imeInTheHistory = imeAndSubtype.first;
2605723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                // If imeId is empty, returns the first IME and subtype in the history
2606723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (TextUtils.isEmpty(imeId) || imeInTheHistory.equals(imeId)) {
2607723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    final String subtypeInTheHistory = imeAndSubtype.second;
2608df31ae6a3011d47421a6ac10021f9649dc34a156satok                    final String subtypeHashCode =
2609df31ae6a3011d47421a6ac10021f9649dc34a156satok                            getEnabledSubtypeHashCodeForInputMethodAndSubtypeLocked(
2610df31ae6a3011d47421a6ac10021f9649dc34a156satok                                    enabledImes, imeInTheHistory, subtypeInTheHistory);
2611723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    if (!TextUtils.isEmpty(subtypeHashCode)) {
2612723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        if (DEBUG) {
2613bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                            Slog.d(TAG, "Enabled subtype found in the history: " + subtypeHashCode);
2614723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        }
2615723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        return new Pair<String, String>(imeInTheHistory, subtypeHashCode);
2616723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    }
2617723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
2618723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2619723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (DEBUG) {
2620723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                Slog.d(TAG, "No enabled IME found in the history");
2621723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2622723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            return null;
2623723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2624723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2625df31ae6a3011d47421a6ac10021f9649dc34a156satok        private String getEnabledSubtypeHashCodeForInputMethodAndSubtypeLocked(List<Pair<String,
2626723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                ArrayList<String>>> enabledImes, String imeId, String subtypeHashCode) {
2627723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            for (Pair<String, ArrayList<String>> enabledIme: enabledImes) {
2628723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (enabledIme.first.equals(imeId)) {
2629f6cafb63753a26440cb3ad2e5124370aef650015satok                    final ArrayList<String> explicitlyEnabledSubtypes = enabledIme.second;
2630f6cafb63753a26440cb3ad2e5124370aef650015satok                    if (explicitlyEnabledSubtypes.size() == 0) {
2631f6cafb63753a26440cb3ad2e5124370aef650015satok                        // If there are no explicitly enabled subtypes, applicable subtypes are
2632f6cafb63753a26440cb3ad2e5124370aef650015satok                        // enabled implicitly.
2633df31ae6a3011d47421a6ac10021f9649dc34a156satok                        InputMethodInfo ime = mMethodMap.get(imeId);
2634df31ae6a3011d47421a6ac10021f9649dc34a156satok                        // If IME is enabled and no subtypes are enabled, applicable subtypes
2635df31ae6a3011d47421a6ac10021f9649dc34a156satok                        // are enabled implicitly, so needs to treat them to be enabled.
2636586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                        if (ime != null && ime.getSubtypeCount() > 0) {
2637df31ae6a3011d47421a6ac10021f9649dc34a156satok                            List<InputMethodSubtype> implicitlySelectedSubtypes =
2638586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                                    getApplicableSubtypesLocked(mRes, getSubtypes(ime));
2639df31ae6a3011d47421a6ac10021f9649dc34a156satok                            if (implicitlySelectedSubtypes != null) {
2640df31ae6a3011d47421a6ac10021f9649dc34a156satok                                final int N = implicitlySelectedSubtypes.size();
2641df31ae6a3011d47421a6ac10021f9649dc34a156satok                                for (int i = 0; i < N; ++i) {
2642df31ae6a3011d47421a6ac10021f9649dc34a156satok                                    final InputMethodSubtype st = implicitlySelectedSubtypes.get(i);
2643df31ae6a3011d47421a6ac10021f9649dc34a156satok                                    if (String.valueOf(st.hashCode()).equals(subtypeHashCode)) {
2644df31ae6a3011d47421a6ac10021f9649dc34a156satok                                        return subtypeHashCode;
2645df31ae6a3011d47421a6ac10021f9649dc34a156satok                                    }
2646df31ae6a3011d47421a6ac10021f9649dc34a156satok                                }
2647df31ae6a3011d47421a6ac10021f9649dc34a156satok                            }
2648df31ae6a3011d47421a6ac10021f9649dc34a156satok                        }
2649df31ae6a3011d47421a6ac10021f9649dc34a156satok                    } else {
2650f6cafb63753a26440cb3ad2e5124370aef650015satok                        for (String s: explicitlyEnabledSubtypes) {
2651df31ae6a3011d47421a6ac10021f9649dc34a156satok                            if (s.equals(subtypeHashCode)) {
2652df31ae6a3011d47421a6ac10021f9649dc34a156satok                                // If both imeId and subtypeId are enabled, return subtypeId.
2653df31ae6a3011d47421a6ac10021f9649dc34a156satok                                return s;
2654df31ae6a3011d47421a6ac10021f9649dc34a156satok                            }
2655723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        }
2656723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    }
2657723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    // If imeId was enabled but subtypeId was disabled.
2658723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    return NOT_A_SUBTYPE_ID_STR;
2659723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
2660723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2661723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // If both imeId and subtypeId are disabled, return null
2662723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            return null;
2663723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2664723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2665723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private List<Pair<String, String>> loadInputMethodAndSubtypeHistoryLocked() {
2666723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            ArrayList<Pair<String, String>> imsList = new ArrayList<Pair<String, String>>();
2667723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            final String subtypeHistoryStr = getSubtypeHistoryStr();
2668723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (TextUtils.isEmpty(subtypeHistoryStr)) {
2669723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                return imsList;
2670723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2671723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mInputMethodSplitter.setString(subtypeHistoryStr);
2672723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            while (mInputMethodSplitter.hasNext()) {
2673723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                String nextImsStr = mInputMethodSplitter.next();
2674723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                mSubtypeSplitter.setString(nextImsStr);
2675723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (mSubtypeSplitter.hasNext()) {
2676723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    String subtypeId = NOT_A_SUBTYPE_ID_STR;
2677723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    // The first element is ime id.
2678723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    String imeId = mSubtypeSplitter.next();
2679723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    while (mSubtypeSplitter.hasNext()) {
2680723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        subtypeId = mSubtypeSplitter.next();
2681723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        break;
2682723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    }
2683723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    imsList.add(new Pair<String, String>(imeId, subtypeId));
2684723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
2685723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2686723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            return imsList;
2687723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2688723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2689723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private String getSubtypeHistoryStr() {
2690723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (DEBUG) {
2691723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                Slog.d(TAG, "getSubtypeHistoryStr: " + Settings.Secure.getString(
2692723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY));
2693723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2694723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            return Settings.Secure.getString(
2695723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY);
2696723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2697723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2698723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public void putSelectedInputMethod(String imeId) {
2699723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            Settings.Secure.putString(mResolver, Settings.Secure.DEFAULT_INPUT_METHOD, imeId);
2700723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2701723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2702723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public void putSelectedSubtype(int subtypeId) {
2703723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            Settings.Secure.putInt(
2704723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    mResolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, subtypeId);
2705723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2706d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    }
2707d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
27089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ----------------------------------------------------------------------
2709ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
27109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
27119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
27129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
27139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                != PackageManager.PERMISSION_GRANTED) {
2714ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
27159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println("Permission Denial: can't dump InputMethodManager from from pid="
27169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + Binder.getCallingPid()
27179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + ", uid=" + Binder.getCallingUid());
27189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
27199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IInputMethod method;
27229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ClientState client;
2723ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
27249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Printer p = new PrintWriterPrinter(pw);
2725ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
27269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
27279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("Current Input Method Manager state:");
27289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int N = mMethodList.size();
27299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  Input Methods:");
27309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i=0; i<N; i++) {
27319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                InputMethodInfo info = mMethodList.get(i);
27329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("  InputMethod #" + i + ":");
27339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                info.dump(p, "    ");
27349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
27359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  Clients:");
27369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (ClientState ci : mClients.values()) {
27379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("  Client " + ci + ":");
27389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("    client=" + ci.client);
27399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("    inputContext=" + ci.inputContext);
27409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("    sessionRequested=" + ci.sessionRequested);
27419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("    curSession=" + ci.curSession);
27429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2743105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            p.println("  mCurMethodId=" + mCurMethodId);
27449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            client = mCurClient;
2745b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            p.println("  mCurClient=" + client + " mCurSeq=" + mCurSeq);
2746b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            p.println("  mCurFocusedWindow=" + mCurFocusedWindow);
27479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mCurId=" + mCurId + " mHaveConnect=" + mHaveConnection
27489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mBoundToMethod=" + mBoundToMethod);
27499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mCurToken=" + mCurToken);
27509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mCurIntent=" + mCurIntent);
27519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            method = mCurMethod;
27529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mCurMethod=" + mCurMethod);
27539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mEnabledSession=" + mEnabledSession);
27549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mShowRequested=" + mShowRequested
27559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
27569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mShowForced=" + mShowForced
27579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mInputShown=" + mInputShown);
2758cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn            p.println("  mSystemReady=" + mSystemReady + " mScreenOn=" + mScreenOn);
27599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2760ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2761b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown        p.println(" ");
27629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (client != null) {
27639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.flush();
27649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
27659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                client.client.asBinder().dump(fd, args);
27669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
27679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("Input method client dead: " + e);
27689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2769b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown        } else {
2770b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown            p.println("No input method client.");
27719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2772ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2773b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown        p.println(" ");
27749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (method != null) {
27759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.flush();
27769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
27779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                method.asBinder().dump(fd, args);
27789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
27799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("Input method service dead: " + e);
27809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2781b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown        } else {
2782b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown            p.println("No input method service.");
27839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2786