InputMethodManagerService.java revision c86884cd839123e3be3cc97c8f293ac47d3624a9
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
2ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker *
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the License at
6ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker *
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
8ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker *
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * License for the specific language governing permissions and limitations under
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the License.
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server;
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackbornimport com.android.internal.content.PackageMonitor;
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.os.HandlerCaller;
20758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganovimport com.android.internal.os.SomeArgs;
21e7c6998e0a953ae55487d4fe122739646f9280aasatokimport com.android.internal.util.FastXmlSerializer;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.IInputContext;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.IInputMethod;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.IInputMethodCallback;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.IInputMethodClient;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.IInputMethodManager;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.IInputMethodSession;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.InputBindResult;
29a924dc0db952fe32509435fdb8dc9c84a9e181f3Dianne Hackbornimport com.android.server.EventLogTags;
3001038492ff0317f0d3cff54d8a7ee36bb31ff175satokimport com.android.server.wm.WindowManagerService;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32e7c6998e0a953ae55487d4fe122739646f9280aasatokimport org.xmlpull.v1.XmlPullParser;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParserException;
34e7c6998e0a953ae55487d4fe122739646f9280aasatokimport org.xmlpull.v1.XmlSerializer;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.ActivityManagerNative;
374e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataokaimport android.app.AppGlobals;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.AlertDialog;
394e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataokaimport android.app.IUserSwitchObserver;
40f90a33e92a7c8d4040c0e660a62336eb7293d785satokimport android.app.KeyguardManager;
417cfc0ed21a3fafabafb40b38a8589808ad1517afsatokimport android.app.Notification;
427cfc0ed21a3fafabafb40b38a8589808ad1517afsatokimport android.app.NotificationManager;
43dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackbornimport android.app.PendingIntent;
445b927c431f54ea47c3333afb7940d79e2e863f1asatokimport android.content.BroadcastReceiver;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ComponentName;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.DialogInterface;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.DialogInterface.OnCancelListener;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
51e7c6998e0a953ae55487d4fe122739646f9280aasatokimport android.content.IntentFilter;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ServiceConnection;
536da35a0c1205398b7df4776e359f7794584fb128Brandon Ballingerimport android.content.pm.ApplicationInfo;
544e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataokaimport android.content.pm.IPackageManager;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
566179ea3196e9306d3f14361fe9ef14191b1edba6Svetoslav Ganovimport android.content.pm.PackageManager.NameNotFoundException;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.ResolveInfo;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.ServiceInfo;
59e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasaniimport android.content.res.Configuration;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.ContentObserver;
63857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onoratoimport android.inputmethodservice.InputMethodService;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
65e7c6998e0a953ae55487d4fe122739646f9280aasatokimport android.os.Environment;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IInterface;
694e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataokaimport android.os.IRemoteCallback;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
714e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataokaimport android.os.Process;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
744df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Projectimport android.os.ResultReceiver;
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
774e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataokaimport android.os.UserHandle;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
79e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasaniimport android.provider.Settings.Secure;
80ab751aa085433e9f735d2e7603459c6c7e9d2fb0satokimport android.provider.Settings.SettingNotFoundException;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils;
82f9f01008624e2d28c15a90d942fa36f98c8c967dsatokimport android.text.style.SuggestionSpan;
8339606a007a5b1309dd000234f2b8cf156c49fd0fDianne Hackbornimport android.util.AtomicFile;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.EventLog;
85f9f01008624e2d28c15a90d942fa36f98c8c967dsatokimport android.util.LruCache;
86ab751aa085433e9f735d2e7603459c6c7e9d2fb0satokimport android.util.Pair;
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.PrintWriterPrinter;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Printer;
89e7c6998e0a953ae55487d4fe122739646f9280aasatokimport android.util.Slog;
90e7c6998e0a953ae55487d4fe122739646f9280aasatokimport android.util.Xml;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.IWindowManager;
9205dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasaimport android.view.LayoutInflater;
9305dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasaimport android.view.View;
9405dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasaimport android.view.ViewGroup;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.WindowManager;
96ab751aa085433e9f735d2e7603459c6c7e9d2fb0satokimport android.view.inputmethod.EditorInfo;
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.inputmethod.InputBinding;
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.inputmethod.InputMethod;
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.inputmethod.InputMethodInfo;
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.inputmethod.InputMethodManager;
101ab751aa085433e9f735d2e7603459c6c7e9d2fb0satokimport android.view.inputmethod.InputMethodSubtype;
10205dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasaimport android.widget.ArrayAdapter;
10301038492ff0317f0d3cff54d8a7ee36bb31ff175satokimport android.widget.CompoundButton;
10401038492ff0317f0d3cff54d8a7ee36bb31ff175satokimport android.widget.CompoundButton.OnCheckedChangeListener;
10505dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasaimport android.widget.RadioButton;
10601038492ff0317f0d3cff54d8a7ee36bb31ff175satokimport android.widget.Switch;
10705dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasaimport android.widget.TextView;
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
109e7c6998e0a953ae55487d4fe122739646f9280aasatokimport java.io.File;
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
111e7c6998e0a953ae55487d4fe122739646f9280aasatokimport java.io.FileInputStream;
112e7c6998e0a953ae55487d4fe122739646f9280aasatokimport java.io.FileOutputStream;
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
116688bd47fccf1a1373e6287bc49b5b33fad12b7f3satokimport java.util.Collections;
117761eb3762f3602dd1859905ee4ba80f0ef6aec56Ken Wakasaimport java.util.Comparator;
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
1197f35c8cc88bea5230f001dd4356f864845d202e5satokimport java.util.HashSet;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List;
1215b927c431f54ea47c3333afb7940d79e2e863f1asatokimport java.util.Locale;
122913a8925c07e854a80bf5df87561f290d3a56d61satokimport java.util.TreeMap;
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This class provides a system service that manages input methods.
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class InputMethodManagerService extends IInputMethodManager.Stub
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        implements ServiceConnection, Handler.Callback {
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final boolean DEBUG = false;
1306ec6f79e1ac1714e3b837796e99f07ff88f66601Jeff Brown    static final String TAG = "InputMethodManagerService";
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_SHOW_IM_PICKER = 1;
133ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    static final int MSG_SHOW_IM_SUBTYPE_PICKER = 2;
13447a44916e2fb33cf4751906386d5f5c903b28d8bsatok    static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 3;
135217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok    static final int MSG_SHOW_IM_CONFIG = 4;
136ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_UNBIND_INPUT = 1000;
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_BIND_INPUT = 1010;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_SHOW_SOFT_INPUT = 1020;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_HIDE_SOFT_INPUT = 1030;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_ATTACH_TOKEN = 1040;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_CREATE_SESSION = 1050;
143ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_START_INPUT = 2000;
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_RESTART_INPUT = 2010;
146ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_UNBIND_METHOD = 3000;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final int MSG_BIND_METHOD = 3010;
149a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn    static final int MSG_SET_ACTIVE = 3020;
150ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
15101038492ff0317f0d3cff54d8a7ee36bb31ff175satok    static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
15201038492ff0317f0d3cff54d8a7ee36bb31ff175satok
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final long TIME_TO_RECONNECT = 10*1000;
154ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
155f9f01008624e2d28c15a90d942fa36f98c8c967dsatok    static final int SECURE_SUGGESTION_SPANS_MAX_SIZE = 20;
156f9f01008624e2d28c15a90d942fa36f98c8c967dsatok
157ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private static final int NOT_A_SUBTYPE_ID = -1;
158723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    private static final String NOT_A_SUBTYPE_ID_STR = String.valueOf(NOT_A_SUBTYPE_ID);
1594e4569dab5c75804b01a19b2d6e6101b445c1c68satok    private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
1604e4569dab5c75804b01a19b2d6e6101b445c1c68satok    private static final String SUBTYPE_MODE_VOICE = "voice";
161b6359414adabab2d64acc8ccc9e3b9c1b800b303satok    private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
162c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok    private static final String TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE =
163c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok            "EnabledWhenDefaultIsNotAsciiCapable";
164c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok    private static final String TAG_ASCII_CAPABLE = "AsciiCapable";
1655b927c431f54ea47c3333afb7940d79e2e863f1asatok    private static final Locale ENGLISH_LOCALE = new Locale("en");
1664e4569dab5c75804b01a19b2d6e6101b445c1c68satok
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final Context mContext;
1687d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn    final Resources mRes;
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final Handler mHandler;
170d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    final InputMethodSettings mSettings;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final SettingsObserver mSettingsObserver;
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final IWindowManager mIWindowManager;
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final HandlerCaller mCaller;
1745ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka    private InputMethodFileManager mFileManager;
1755ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka    private InputMethodAndSubtypeListManager mImListManager;
17601038492ff0317f0d3cff54d8a7ee36bb31ff175satok    private final HardKeyboardListener mHardKeyboardListener;
17701038492ff0317f0d3cff54d8a7ee36bb31ff175satok    private final WindowManagerService mWindowManagerService;
178ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final InputBindResult mNoBinding = new InputBindResult(null, null, -1);
180ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // All known input methods.  mMethodMap also serves as the global
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // lock for this class.
183d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    final ArrayList<InputMethodInfo> mMethodList = new ArrayList<InputMethodInfo>();
184d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    final HashMap<String, InputMethodInfo> mMethodMap = new HashMap<String, InputMethodInfo>();
185f9f01008624e2d28c15a90d942fa36f98c8c967dsatok    private final LruCache<SuggestionSpan, InputMethodInfo> mSecureSuggestionSpans =
186f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            new LruCache<SuggestionSpan, InputMethodInfo>(SECURE_SUGGESTION_SPANS_MAX_SIZE);
187ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1882c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn    // Used to bring IME service up to visible adjustment while it is being shown.
1892c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn    final ServiceConnection mVisibleConnection = new ServiceConnection() {
1902c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn        @Override public void onServiceConnected(ComponentName name, IBinder service) {
1912c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn        }
1922c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn
1932c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn        @Override public void onServiceDisconnected(ComponentName name) {
1942c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn        }
1952c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn    };
1962c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn    boolean mVisibleBound = false;
1972c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn
1987cfc0ed21a3fafabafb40b38a8589808ad1517afsatok    // Ongoing notification
199661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn    private NotificationManager mNotificationManager;
200661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn    private KeyguardManager mKeyguardManager;
201661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn    private StatusBarManagerService mStatusBar;
202661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn    private Notification mImeSwitcherNotification;
203661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn    private PendingIntent mImeSwitchPendingIntent;
204b858c732f665fe9610f2d913230ae625f44a8caasatok    private boolean mShowOngoingImeSwitcherForPhones;
2057cfc0ed21a3fafabafb40b38a8589808ad1517afsatok    private boolean mNotificationShown;
2060a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok    private final boolean mImeSelectedOnBoot;
2077cfc0ed21a3fafabafb40b38a8589808ad1517afsatok
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class SessionState {
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ClientState client;
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final IInputMethod method;
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final IInputMethodSession session;
212ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "SessionState{uid " + client.uid + " pid " + client.pid
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " method " + Integer.toHexString(
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            System.identityHashCode(method))
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " session " + Integer.toHexString(
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            System.identityHashCode(session))
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + "}";
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SessionState(ClientState _client, IInputMethod _method,
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                IInputMethodSession _session) {
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            client = _client;
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            method = _method;
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            session = _session;
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
230ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class ClientState {
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final IInputMethodClient client;
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final IInputContext inputContext;
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int uid;
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int pid;
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final InputBinding binding;
237ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean sessionRequested;
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SessionState curSession;
240ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "ClientState{" + Integer.toHexString(
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    System.identityHashCode(this)) + " uid " + uid
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " pid " + pid + "}";
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ClientState(IInputMethodClient _client, IInputContext _inputContext,
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int _uid, int _pid) {
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            client = _client;
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            inputContext = _inputContext;
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uid = _uid;
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pid = _pid;
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
257ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final HashMap<IBinder, ClientState> mClients
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            = new HashMap<IBinder, ClientState>();
260ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
262a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn     * Set once the system is ready to run third party code.
263a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn     */
264a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn    boolean mSystemReady;
265ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
266a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn    /**
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Id of the currently selected input method.
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    String mCurMethodId;
270ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The current binding sequence number, incremented every time there is
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * a new bind performed.
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int mCurSeq;
276ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The client that is currently bound to an input method.
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ClientState mCurClient;
281ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
283b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project     * The last window token that gained focus.
284b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project     */
285b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    IBinder mCurFocusedWindow;
286ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
287b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    /**
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The input context last provided by the current client.
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    IInputContext mCurInputContext;
291ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The attributes last provided by the current client.
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    EditorInfo mCurAttribute;
296ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The input method ID of the input method service that we are currently
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * connected to or in the process of connecting to.
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    String mCurId;
302ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
304ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * The current subtype of the current input method.
305ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     */
306ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private InputMethodSubtype mCurrentSubtype;
307ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
3084e4569dab5c75804b01a19b2d6e6101b445c1c68satok    // This list contains the pairs of InputMethodInfo and InputMethodSubtype.
309f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok    private final HashMap<InputMethodInfo, ArrayList<InputMethodSubtype>>
310f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            mShortcutInputMethodsAndSubtypes =
311f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                new HashMap<InputMethodInfo, ArrayList<InputMethodSubtype>>();
312ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
313ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    /**
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set to true if our ServiceConnection is currently actively bound to
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * a service (whether or not we have gotten its IBinder back yet).
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mHaveConnection;
318ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set if the client has asked for the input method to be shown.
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mShowRequested;
323ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set if we were explicitly told to show the input method.
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mShowExplicitlyRequested;
328ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set if we were forced to be shown.
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mShowForced;
333ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set if we last told the input method to show itself.
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mInputShown;
338ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The Intent used to connect to the current input method.
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Intent mCurIntent;
343ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The token we have made for the currently active input method, to
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * identify it in the future.
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    IBinder mCurToken;
349ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If non-null, this is the input method service we are currently connected
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to.
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    IInputMethod mCurMethod;
355ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Time that we last initiated a bind to the input method, to determine
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * if we should try to disconnect and reconnect to it.
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long mLastBindTime;
361ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Have we called mCurMethod.bindInput()?
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mBoundToMethod;
366ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Currently enabled session.  Only touched by service thread, not
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * protected by a lock.
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SessionState mEnabledSession;
372ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * True if the screen is on.  The value is true initially.
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mScreenOn = true;
377ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
378857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato    int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
379857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato    int mImeWindowVis;
380857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato
38105dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa    private AlertDialog.Builder mDialogBuilder;
38205dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa    private AlertDialog mSwitchingDialog;
38301038492ff0317f0d3cff54d8a7ee36bb31ff175satok    private View mSwitchingDialogTitleView;
38405dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa    private InputMethodInfo[] mIms;
38505dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa    private int[] mSubtypeIds;
3865b927c431f54ea47c3333afb7940d79e2e863f1asatok    private Locale mLastSystemLocale;
3874e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
3884e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    private final IPackageManager mIPackageManager;
389ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class SettingsObserver extends ContentObserver {
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SettingsObserver(Handler handler) {
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(handler);
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ContentResolver resolver = mContext.getContentResolver();
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            resolver.registerContentObserver(Settings.Secure.getUriFor(
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
396ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            resolver.registerContentObserver(Settings.Secure.getUriFor(
397b6109bb591bc02bf8a2d9d5ca76d69d1961c9b5fsatok                    Settings.Secure.ENABLED_INPUT_METHODS), false, this);
398b6109bb591bc02bf8a2d9d5ca76d69d1961c9b5fsatok            resolver.registerContentObserver(Settings.Secure.getUriFor(
399ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this);
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
401ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override public void onChange(boolean selfChange) {
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                updateFromSettingsLocked();
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
408ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
4094e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    class ImmsBroadcastReceiver extends android.content.BroadcastReceiver {
4104e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        private void updateActive() {
4114e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            // Inform the current client of the change in active status
4124e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (mCurClient != null && mCurClient.client != null) {
4134e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
4144e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        MSG_SET_ACTIVE, mScreenOn ? 1 : 0, mCurClient));
4154e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
4164e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
4174e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
4204e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            final String action = intent.getAction();
4214e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (Intent.ACTION_SCREEN_ON.equals(action)) {
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mScreenOn = true;
4233afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok                refreshImeWindowVisibilityLocked();
4244e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                updateActive();
4254e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                return;
4264e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mScreenOn = false;
42815452a487a4c0274f4217cd060aa54446f30a8f3satok                setImeWindowVisibilityStatusHiddenLocked();
4294e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                updateActive();
4304e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                return;
4314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            } else if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
432105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                hideInputMethodMenu();
4334e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                // No need to updateActive
434105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                return;
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
4368a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Unexpected intent " + intent);
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
440ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
44121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    class MyPackageMonitor extends PackageMonitor {
4424e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        private boolean isChangingPackagesOfCurrentUser() {
4434e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            final int userId = getChangingUserId();
4444e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            final boolean retval = userId == mSettings.getCurrentUserId();
4454e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
4464e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "--- ignore this call back from a background user: " + userId);
4474e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
4484e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return retval;
4494e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
4504e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
45221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
4534e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (!isChangingPackagesOfCurrentUser()) {
4544e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                return false;
4554e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
45621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            synchronized (mMethodMap) {
4574e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                String curInputMethodId = mSettings.getSelectedInputMethod();
45821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                final int N = mMethodList.size();
45921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                if (curInputMethodId != null) {
46021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    for (int i=0; i<N; i++) {
46121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        InputMethodInfo imi = mMethodList.get(i);
46221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        if (imi.getId().equals(curInputMethodId)) {
46321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            for (String pkg : packages) {
46421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                if (imi.getPackageName().equals(pkg)) {
46521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    if (!doit) {
46621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                        return true;
46721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    }
468723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                                    resetSelectedInputMethodAndSubtypeLocked("");
46921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    chooseNewDefaultIMELocked();
47021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    return true;
47121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                }
47221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            }
47321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        }
47421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    }
47508675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                }
47608675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu            }
47721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            return false;
47821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        }
479ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
48021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        @Override
48121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        public void onSomePackagesChanged() {
4824e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (!isChangingPackagesOfCurrentUser()) {
4834e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                return;
4844e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
48521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            synchronized (mMethodMap) {
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                InputMethodInfo curIm = null;
4874e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                String curInputMethodId = mSettings.getSelectedInputMethod();
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int N = mMethodList.size();
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (curInputMethodId != null) {
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (int i=0; i<N; i++) {
49121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        InputMethodInfo imi = mMethodList.get(i);
492e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final String imiId = imi.getId();
493e7c6998e0a953ae55487d4fe122739646f9280aasatok                        if (imiId.equals(curInputMethodId)) {
49421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            curIm = imi;
49521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        }
496e7c6998e0a953ae55487d4fe122739646f9280aasatok
49721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        int change = isPackageDisappearing(imi.getPackageName());
498e7c6998e0a953ae55487d4fe122739646f9280aasatok                        if (isPackageModified(imi.getPackageName())) {
499e7c6998e0a953ae55487d4fe122739646f9280aasatok                            mFileManager.deleteAllInputMethodSubtypes(imiId);
500e7c6998e0a953ae55487d4fe122739646f9280aasatok                        }
50121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        if (change == PACKAGE_TEMPORARY_CHANGE
50221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                || change == PACKAGE_PERMANENT_CHANGE) {
5038a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            Slog.i(TAG, "Input method uninstalled, disabling: "
50421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    + imi.getComponent());
50521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            setInputMethodEnabledLocked(imi.getId(), false);
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
509ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
51021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                buildInputMethodListLocked(mMethodList, mMethodMap);
51121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean changed = false;
513ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
51408675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                if (curIm != null) {
51521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    int change = isPackageDisappearing(curIm.getPackageName());
51621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    if (change == PACKAGE_TEMPORARY_CHANGE
51721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            || change == PACKAGE_PERMANENT_CHANGE) {
51808675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        ServiceInfo si = null;
51908675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        try {
5204e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                            si = mIPackageManager.getServiceInfo(
5214e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                    curIm.getComponent(), 0, mSettings.getCurrentUserId());
5224e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        } catch (RemoteException ex) {
52308675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        }
52408675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        if (si == null) {
52508675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                            // Uh oh, current input method is no longer around!
52608675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                            // Pick another one...
5278a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            Slog.i(TAG, "Current input method removed: " + curInputMethodId);
52815452a487a4c0274f4217cd060aa54446f30a8f3satok                            setImeWindowVisibilityStatusHiddenLocked();
52921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            if (!chooseNewDefaultIMELocked()) {
53008675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                                changed = true;
53108675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                                curIm = null;
5328a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                                Slog.i(TAG, "Unsetting current input method");
533723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                                resetSelectedInputMethodAndSubtypeLocked("");
53408675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                            }
53508675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        }
53608675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                    }
53721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                }
538ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
53921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                if (curIm == null) {
54021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    // We currently don't have a default input method... is
54121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    // one now available?
54221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    changed = chooseNewDefaultIMELocked();
54321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                }
544ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
54521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                if (changed) {
54621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    updateFromSettingsLocked();
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
551ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
552e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard    private static class MethodCallback extends IInputMethodCallback.Stub {
553e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard        private final IInputMethod mMethod;
554e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard        private final InputMethodManagerService mParentIMMS;
555ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
556e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard        MethodCallback(final IInputMethod method, final InputMethodManagerService imms) {
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMethod = method;
558e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard            mParentIMMS = imms;
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
560ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
561e7c6998e0a953ae55487d4fe122739646f9280aasatok        @Override
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void finishedEvent(int seq, boolean handled) throws RemoteException {
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
565e7c6998e0a953ae55487d4fe122739646f9280aasatok        @Override
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void sessionCreated(IInputMethodSession session) throws RemoteException {
567e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard            mParentIMMS.onSessionCreated(mMethod, session);
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
570ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
57101038492ff0317f0d3cff54d8a7ee36bb31ff175satok    private class HardKeyboardListener
57201038492ff0317f0d3cff54d8a7ee36bb31ff175satok            implements WindowManagerService.OnHardKeyboardStatusChangeListener {
57301038492ff0317f0d3cff54d8a7ee36bb31ff175satok        @Override
57401038492ff0317f0d3cff54d8a7ee36bb31ff175satok        public void onHardKeyboardStatusChange(boolean available, boolean enabled) {
57501038492ff0317f0d3cff54d8a7ee36bb31ff175satok            mHandler.sendMessage(mHandler.obtainMessage(
57601038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    MSG_HARD_KEYBOARD_SWITCH_CHANGED, available ? 1 : 0, enabled ? 1 : 0));
57701038492ff0317f0d3cff54d8a7ee36bb31ff175satok        }
57801038492ff0317f0d3cff54d8a7ee36bb31ff175satok
57901038492ff0317f0d3cff54d8a7ee36bb31ff175satok        public void handleHardKeyboardStatusChange(boolean available, boolean enabled) {
58001038492ff0317f0d3cff54d8a7ee36bb31ff175satok            if (DEBUG) {
58101038492ff0317f0d3cff54d8a7ee36bb31ff175satok                Slog.w(TAG, "HardKeyboardStatusChanged: available = " + available + ", enabled = "
58201038492ff0317f0d3cff54d8a7ee36bb31ff175satok                        + enabled);
58301038492ff0317f0d3cff54d8a7ee36bb31ff175satok            }
58401038492ff0317f0d3cff54d8a7ee36bb31ff175satok            synchronized(mMethodMap) {
58501038492ff0317f0d3cff54d8a7ee36bb31ff175satok                if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
58601038492ff0317f0d3cff54d8a7ee36bb31ff175satok                        && mSwitchingDialog.isShowing()) {
58701038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    mSwitchingDialogTitleView.findViewById(
58801038492ff0317f0d3cff54d8a7ee36bb31ff175satok                            com.android.internal.R.id.hard_keyboard_section).setVisibility(
58901038492ff0317f0d3cff54d8a7ee36bb31ff175satok                                    available ? View.VISIBLE : View.GONE);
59001038492ff0317f0d3cff54d8a7ee36bb31ff175satok                }
59101038492ff0317f0d3cff54d8a7ee36bb31ff175satok            }
59201038492ff0317f0d3cff54d8a7ee36bb31ff175satok        }
59301038492ff0317f0d3cff54d8a7ee36bb31ff175satok    }
59401038492ff0317f0d3cff54d8a7ee36bb31ff175satok
59501038492ff0317f0d3cff54d8a7ee36bb31ff175satok    public InputMethodManagerService(Context context, WindowManagerService windowManager) {
5964e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        mIPackageManager = AppGlobals.getPackageManager();
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
5987d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn        mRes = context.getResources();
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler = new Handler(this);
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIWindowManager = IWindowManager.Stub.asInterface(
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ServiceManager.getService(Context.WINDOW_SERVICE));
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCaller = new HandlerCaller(context, new HandlerCaller.Callback() {
603e7c6998e0a953ae55487d4fe122739646f9280aasatok            @Override
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void executeMessage(Message msg) {
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handleMessage(msg);
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        });
60801038492ff0317f0d3cff54d8a7ee36bb31ff175satok        mWindowManagerService = windowManager;
60901038492ff0317f0d3cff54d8a7ee36bb31ff175satok        mHardKeyboardListener = new HardKeyboardListener();
6107cfc0ed21a3fafabafb40b38a8589808ad1517afsatok
6117cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification = new Notification();
6127cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification.icon = com.android.internal.R.drawable.ic_notification_ime_default;
6137cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification.when = 0;
6147cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification.flags = Notification.FLAG_ONGOING_EVENT;
6157cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification.tickerText = null;
6167cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification.defaults = 0; // please be quiet
6177cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification.sound = null;
6187cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification.vibrate = null;
619590d515d912396a0c293d78529ac0dbc224400bfDaniel Sandler
620590d515d912396a0c293d78529ac0dbc224400bfDaniel Sandler        // Tag this notification specially so SystemUI knows it's important
621590d515d912396a0c293d78529ac0dbc224400bfDaniel Sandler        mImeSwitcherNotification.kind = new String[] { "android.system.imeswitcher" };
622590d515d912396a0c293d78529ac0dbc224400bfDaniel Sandler
6237cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
624683e2383c8549f95e00bade15daed3dbddf13950satok        mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
625b858c732f665fe9610f2d913230ae625f44a8caasatok
626b858c732f665fe9610f2d913230ae625f44a8caasatok        mShowOngoingImeSwitcherForPhones = false;
6277cfc0ed21a3fafabafb40b38a8589808ad1517afsatok
6284e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final IntentFilter broadcastFilter = new IntentFilter();
6294e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        broadcastFilter.addAction(Intent.ACTION_SCREEN_ON);
6304e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        broadcastFilter.addAction(Intent.ACTION_SCREEN_OFF);
6314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        broadcastFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
6324e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        mContext.registerReceiver(new ImmsBroadcastReceiver(), broadcastFilter);
633ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
6347cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mNotificationShown = false;
6354e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        int userId = 0;
6364e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        try {
6374e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            ActivityManagerNative.getDefault().registerUserSwitchObserver(
6384e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    new IUserSwitchObserver.Stub() {
6394e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        @Override
6404e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        public void onUserSwitching(int newUserId, IRemoteCallback reply) {
6415ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka                            synchronized(mMethodMap) {
6425ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka                                switchUserLocked(newUserId);
6435ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka                            }
6444e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                            if (reply != null) {
6454e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                try {
6464e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                    reply.sendResult(null);
6474e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                } catch (RemoteException e) {
6484e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                }
6494e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                            }
6504e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        }
6514e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
6524e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        @Override
6534e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        public void onUserSwitchComplete(int newUserId) throws RemoteException {
6544e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        }
6554e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    });
6564e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            userId = ActivityManagerNative.getDefault().getCurrentUser().id;
6574e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        } catch (RemoteException e) {
6584e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
6594e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
6604e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        mMyPackageMonitor.register(mContext, null, true);
661913a8925c07e854a80bf5df87561f290d3a56d61satok
662d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // mSettings should be created before buildInputMethodListLocked
663df31ae6a3011d47421a6ac10021f9649dc34a156satok        mSettings = new InputMethodSettings(
6644e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                mRes, context.getContentResolver(), mMethodMap, mMethodList, userId);
6655ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka        mFileManager = new InputMethodFileManager(mMethodMap, userId);
6665ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka        mImListManager = new InputMethodAndSubtypeListManager(context, this);
6670a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok
6680a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok        // Just checking if defaultImiId is empty or not
6694e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final String defaultImiId = mSettings.getSelectedInputMethod();
6700a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok        mImeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
6710a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        buildInputMethodListLocked(mMethodList, mMethodMap);
673d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        mSettings.enableAllIMEsIfThereIsNoEnabledIME();
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6750a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok        if (!mImeSelectedOnBoot) {
6760a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            Slog.w(TAG, "No IME selected. Choose the most applicable IME.");
6775b927c431f54ea47c3333afb7940d79e2e863f1asatok            resetDefaultImeLocked(context);
6785b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
6795b927c431f54ea47c3333afb7940d79e2e863f1asatok
6805b927c431f54ea47c3333afb7940d79e2e863f1asatok        mSettingsObserver = new SettingsObserver(mHandler);
6815b927c431f54ea47c3333afb7940d79e2e863f1asatok        updateFromSettingsLocked();
6825b927c431f54ea47c3333afb7940d79e2e863f1asatok
6835b927c431f54ea47c3333afb7940d79e2e863f1asatok        // IMMS wants to receive Intent.ACTION_LOCALE_CHANGED in order to update the current IME
6845b927c431f54ea47c3333afb7940d79e2e863f1asatok        // according to the new system locale.
6855b927c431f54ea47c3333afb7940d79e2e863f1asatok        final IntentFilter filter = new IntentFilter();
6865b927c431f54ea47c3333afb7940d79e2e863f1asatok        filter.addAction(Intent.ACTION_LOCALE_CHANGED);
6875b927c431f54ea47c3333afb7940d79e2e863f1asatok        mContext.registerReceiver(
6885b927c431f54ea47c3333afb7940d79e2e863f1asatok                new BroadcastReceiver() {
6895b927c431f54ea47c3333afb7940d79e2e863f1asatok                    @Override
6905b927c431f54ea47c3333afb7940d79e2e863f1asatok                    public void onReceive(Context context, Intent intent) {
6915b927c431f54ea47c3333afb7940d79e2e863f1asatok                        synchronized(mMethodMap) {
6925b927c431f54ea47c3333afb7940d79e2e863f1asatok                            checkCurrentLocaleChangedLocked();
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
6955b927c431f54ea47c3333afb7940d79e2e863f1asatok                }, filter);
6965b927c431f54ea47c3333afb7940d79e2e863f1asatok    }
6975b927c431f54ea47c3333afb7940d79e2e863f1asatok
6985b927c431f54ea47c3333afb7940d79e2e863f1asatok    private void resetDefaultImeLocked(Context context) {
6995b927c431f54ea47c3333afb7940d79e2e863f1asatok        // Do not reset the default (current) IME when it is a 3rd-party IME
7005b927c431f54ea47c3333afb7940d79e2e863f1asatok        if (mCurMethodId != null && !isSystemIme(mMethodMap.get(mCurMethodId))) {
7015b927c431f54ea47c3333afb7940d79e2e863f1asatok            return;
7025b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
7035b927c431f54ea47c3333afb7940d79e2e863f1asatok
7045b927c431f54ea47c3333afb7940d79e2e863f1asatok        InputMethodInfo defIm = null;
7055b927c431f54ea47c3333afb7940d79e2e863f1asatok        for (InputMethodInfo imi : mMethodList) {
7065b927c431f54ea47c3333afb7940d79e2e863f1asatok            if (defIm == null) {
7075b927c431f54ea47c3333afb7940d79e2e863f1asatok                if (isValidSystemDefaultIme(imi, context)) {
7085b927c431f54ea47c3333afb7940d79e2e863f1asatok                    defIm = imi;
7095b927c431f54ea47c3333afb7940d79e2e863f1asatok                    Slog.i(TAG, "Selected default: " + imi.getId());
7105b927c431f54ea47c3333afb7940d79e2e863f1asatok                }
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7125b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
7135b927c431f54ea47c3333afb7940d79e2e863f1asatok        if (defIm == null && mMethodList.size() > 0) {
7145b927c431f54ea47c3333afb7940d79e2e863f1asatok            defIm = getMostApplicableDefaultIMELocked();
7155b927c431f54ea47c3333afb7940d79e2e863f1asatok            Slog.i(TAG, "No default found, using " + defIm.getId());
7165b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
7175b927c431f54ea47c3333afb7940d79e2e863f1asatok        if (defIm != null) {
7185b927c431f54ea47c3333afb7940d79e2e863f1asatok            setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
7195b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
7205b927c431f54ea47c3333afb7940d79e2e863f1asatok    }
7215b927c431f54ea47c3333afb7940d79e2e863f1asatok
7224e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    private void resetAllInternalStateLocked(boolean updateOnlyWhenLocaleChanged) {
7234e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!mSystemReady) {
7244e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            // not system ready
7254e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
7264e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
7274e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final Locale newLocale = mRes.getConfiguration().locale;
7284e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!updateOnlyWhenLocaleChanged
7294e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                || (newLocale != null && !newLocale.equals(mLastSystemLocale))) {
7304e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (!updateOnlyWhenLocaleChanged) {
7314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                hideCurrentInputLocked(0, null);
7324e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                mCurMethodId = null;
7334e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                unbindCurrentMethodLocked(true);
7344e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
7354e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
7364e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.i(TAG, "Locale has been changed to " + newLocale);
7374e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
7385ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka            // InputMethodAndSubtypeListManager should be reset when the locale is changed.
7395ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka            mImListManager = new InputMethodAndSubtypeListManager(mContext, this);
7404e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            buildInputMethodListLocked(mMethodList, mMethodMap);
7414e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (!updateOnlyWhenLocaleChanged) {
7424e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                final String selectedImiId = mSettings.getSelectedInputMethod();
7434e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                if (TextUtils.isEmpty(selectedImiId)) {
7444e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    // This is the first time of the user switch and
7454e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    // set the current ime to the proper one.
7464e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    resetDefaultImeLocked(mContext);
7474e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                }
748d08a9238db0de62c956788ceebb227d099ad88c2Satoshi Kataoka            } else {
749d08a9238db0de62c956788ceebb227d099ad88c2Satoshi Kataoka                // If the locale is changed, needs to reset the default ime
750d08a9238db0de62c956788ceebb227d099ad88c2Satoshi Kataoka                resetDefaultImeLocked(mContext);
7514e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
7524e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            updateFromSettingsLocked();
7534e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            mLastSystemLocale = newLocale;
7544e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (!updateOnlyWhenLocaleChanged) {
7554e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                try {
7564e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    startInputInnerLocked();
7574e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                } catch (RuntimeException e) {
7584e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    Slog.w(TAG, "Unexpected exception", e);
7594e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                }
7604e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
7614e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
7624e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    }
7634e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
7644e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    private void checkCurrentLocaleChangedLocked() {
7654e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        resetAllInternalStateLocked(true);
7664e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    }
7674e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
7685ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka    private void switchUserLocked(int newUserId) {
7694e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        mSettings.setCurrentUserId(newUserId);
7705ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka        // InputMethodFileManager should be reset when the user is changed
7715ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka        mFileManager = new InputMethodFileManager(mMethodMap, newUserId);
7724e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        resetAllInternalStateLocked(false);
7734e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    }
7744e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
7750a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok    private boolean isValidSystemDefaultIme(InputMethodInfo imi, Context context) {
7760a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok        if (!mSystemReady) {
7770a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            return false;
7780a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok        }
7795b927c431f54ea47c3333afb7940d79e2e863f1asatok        if (!isSystemIme(imi)) {
7805b927c431f54ea47c3333afb7940d79e2e863f1asatok            return false;
7815b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
7825b927c431f54ea47c3333afb7940d79e2e863f1asatok        if (imi.getIsDefaultResourceId() != 0) {
7835b927c431f54ea47c3333afb7940d79e2e863f1asatok            try {
7845b927c431f54ea47c3333afb7940d79e2e863f1asatok                Resources res = context.createPackageContext(
7855b927c431f54ea47c3333afb7940d79e2e863f1asatok                        imi.getPackageName(), 0).getResources();
7865b927c431f54ea47c3333afb7940d79e2e863f1asatok                if (res.getBoolean(imi.getIsDefaultResourceId())
7875b927c431f54ea47c3333afb7940d79e2e863f1asatok                        && containsSubtypeOf(imi, context.getResources().getConfiguration().
7885b927c431f54ea47c3333afb7940d79e2e863f1asatok                                locale.getLanguage())) {
7895b927c431f54ea47c3333afb7940d79e2e863f1asatok                    return true;
7905b927c431f54ea47c3333afb7940d79e2e863f1asatok                }
7915b927c431f54ea47c3333afb7940d79e2e863f1asatok            } catch (PackageManager.NameNotFoundException ex) {
7925b927c431f54ea47c3333afb7940d79e2e863f1asatok            } catch (Resources.NotFoundException ex) {
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7955b927c431f54ea47c3333afb7940d79e2e863f1asatok        if (imi.getSubtypeCount() == 0) {
7965b927c431f54ea47c3333afb7940d79e2e863f1asatok            Slog.w(TAG, "Found no subtypes in a system IME: " + imi.getPackageName());
7975b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
7985b927c431f54ea47c3333afb7940d79e2e863f1asatok        return false;
7995b927c431f54ea47c3333afb7940d79e2e863f1asatok    }
800ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
8015b927c431f54ea47c3333afb7940d79e2e863f1asatok    private static boolean isSystemImeThatHasEnglishSubtype(InputMethodInfo imi) {
8025b927c431f54ea47c3333afb7940d79e2e863f1asatok        if (!isSystemIme(imi)) {
8035b927c431f54ea47c3333afb7940d79e2e863f1asatok            return false;
8045b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
8055b927c431f54ea47c3333afb7940d79e2e863f1asatok        return containsSubtypeOf(imi, ENGLISH_LOCALE.getLanguage());
8065b927c431f54ea47c3333afb7940d79e2e863f1asatok    }
8075b927c431f54ea47c3333afb7940d79e2e863f1asatok
8085b927c431f54ea47c3333afb7940d79e2e863f1asatok    private static boolean containsSubtypeOf(InputMethodInfo imi, String language) {
8095b927c431f54ea47c3333afb7940d79e2e863f1asatok        final int N = imi.getSubtypeCount();
8105b927c431f54ea47c3333afb7940d79e2e863f1asatok        for (int i = 0; i < N; ++i) {
8115b927c431f54ea47c3333afb7940d79e2e863f1asatok            if (imi.getSubtypeAt(i).getLocale().startsWith(language)) {
8125b927c431f54ea47c3333afb7940d79e2e863f1asatok                return true;
8135b927c431f54ea47c3333afb7940d79e2e863f1asatok            }
8145b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
8155b927c431f54ea47c3333afb7940d79e2e863f1asatok        return false;
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws RemoteException {
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return super.onTransact(code, data, reply, flags);
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (RuntimeException e) {
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // The input method manager only throws security exceptions, so let's
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // log all others.
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!(e instanceof SecurityException)) {
8278a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.e(TAG, "Input Method Manager Crash", e);
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw e;
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
833661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn    public void systemReady(StatusBarManagerService statusBar) {
834a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        synchronized (mMethodMap) {
8354e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
8364e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "--- systemReady");
8374e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
838a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            if (!mSystemReady) {
839a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn                mSystemReady = true;
8404e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                mKeyguardManager =
8414e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
842661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                mNotificationManager = (NotificationManager)
843661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
844661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                mStatusBar = statusBar;
845661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                statusBar.setIconVisibility("ime", false);
846661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                updateImeWindowStatusLocked();
847b858c732f665fe9610f2d913230ae625f44a8caasatok                mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
848b858c732f665fe9610f2d913230ae625f44a8caasatok                        com.android.internal.R.bool.show_ongoing_ime_switcher);
84901038492ff0317f0d3cff54d8a7ee36bb31ff175satok                if (mShowOngoingImeSwitcherForPhones) {
85001038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    mWindowManagerService.setOnHardKeyboardStatusChangeListener(
85101038492ff0317f0d3cff54d8a7ee36bb31ff175satok                            mHardKeyboardListener);
85201038492ff0317f0d3cff54d8a7ee36bb31ff175satok                }
8530a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                buildInputMethodListLocked(mMethodList, mMethodMap);
8540a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                if (!mImeSelectedOnBoot) {
8550a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                    Slog.w(TAG, "Reset the default IME as \"Resource\" is ready here.");
8560a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                    checkCurrentLocaleChangedLocked();
8570a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                }
8580a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                mLastSystemLocale = mRes.getConfiguration().locale;
859cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                try {
860cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                    startInputInnerLocked();
861cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                } catch (RuntimeException e) {
8628a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.w(TAG, "Unexpected exception", e);
863cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                }
864a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            }
865a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        }
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
867ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
86815452a487a4c0274f4217cd060aa54446f30a8f3satok    private void setImeWindowVisibilityStatusHiddenLocked() {
86915452a487a4c0274f4217cd060aa54446f30a8f3satok        mImeWindowVis = 0;
87015452a487a4c0274f4217cd060aa54446f30a8f3satok        updateImeWindowStatusLocked();
87115452a487a4c0274f4217cd060aa54446f30a8f3satok    }
87215452a487a4c0274f4217cd060aa54446f30a8f3satok
8733afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok    private void refreshImeWindowVisibilityLocked() {
8743afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok        final Configuration conf = mRes.getConfiguration();
8753afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok        final boolean haveHardKeyboard = conf.keyboard
8763afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok                != Configuration.KEYBOARD_NOKEYS;
8773afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok        final boolean hardKeyShown = haveHardKeyboard
8783afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok                && conf.hardKeyboardHidden
8793afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok                        != Configuration.HARDKEYBOARDHIDDEN_YES;
8803afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok        final boolean isScreenLocked = mKeyguardManager != null
8813afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok                && mKeyguardManager.isKeyguardLocked()
8823afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok                && mKeyguardManager.isKeyguardSecure();
8833afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok        mImeWindowVis = (!isScreenLocked && (mInputShown || hardKeyShown)) ?
8843afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok                (InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE) : 0;
8853afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok        updateImeWindowStatusLocked();
8863afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok    }
8873afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok
88815452a487a4c0274f4217cd060aa54446f30a8f3satok    private void updateImeWindowStatusLocked() {
889dbf2950781ab0c4c0fc4ad9bd71b13c55ae6f471satok        setImeWindowStatus(mCurToken, mImeWindowVis, mBackDisposition);
890661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn    }
891661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn
8924e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    // ---------------------------------------------------------------------------------------
8934e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    // Check whether or not this is a valid IPC. Assumes an IPC is valid when either
8944e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    // 1) it comes from the system process
8954e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    // 2) the calling process' user id is identical to the current user id IMMS thinks.
8964e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    private boolean calledFromValidUser() {
8974e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final int uid = Binder.getCallingUid();
8984e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final int userId = UserHandle.getUserId(uid);
8994e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (DEBUG) {
9004e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
9014e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
9024e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    + " calling userId = " + userId + ", foreground user id = "
903c86884cd839123e3be3cc97c8f293ac47d3624a9Satoshi Kataoka                    + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid());
9044e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
9054e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (uid == Process.SYSTEM_UID || userId == mSettings.getCurrentUserId()) {
9064e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return true;
9074e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
908135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka
909135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        // Caveat: A process which has INTERACT_ACROSS_USERS_FULL gets results for the
910135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        // foreground user, not for the user of that process. Accordingly InputMethodManagerService
911135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        // must not manage background users' states in any functions.
912135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        // Note that privacy-sensitive IPCs, such as setInputMethod, are still securely guarded
913135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        // by a token.
914135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        if (mContext.checkCallingOrSelfPermission(
915135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
916135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        == PackageManager.PERMISSION_GRANTED) {
917135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka            if (DEBUG) {
918135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                Slog.d(TAG, "--- Access granted because the calling process has "
919135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        + "the INTERACT_ACROSS_USERS_FULL permission");
920135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka            }
921135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka            return true;
922135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        }
923135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        Slog.w(TAG, "--- IPC called from background users. Ignore. \n" + getStackTrace());
924135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        return false;
9254e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    }
9264e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
9274e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    private boolean bindCurrentInputMethodService(
9284e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Intent service, ServiceConnection conn, int flags) {
9294e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (service == null || conn == null) {
9304e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn);
9314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
9324e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
9334e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        return mContext.bindService(service, conn, flags, mSettings.getCurrentUserId());
9344e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    }
9354e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
936e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public List<InputMethodInfo> getInputMethodList() {
9384e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // TODO: Make this work even for non-current users?
9394e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
9404e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return Collections.emptyList();
9414e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new ArrayList<InputMethodInfo>(mMethodList);
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
947e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public List<InputMethodInfo> getEnabledInputMethodList() {
9494e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // TODO: Make this work even for non-current users?
9504e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
9514e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return Collections.emptyList();
9524e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
954d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return mSettings.getEnabledInputMethodListLocked();
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
958bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok    private HashMap<InputMethodInfo, List<InputMethodSubtype>>
959bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            getExplicitlyOrImplicitlyEnabledInputMethodsAndSubtypeListLocked() {
960bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        HashMap<InputMethodInfo, List<InputMethodSubtype>> enabledInputMethodAndSubtypes =
961bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                new HashMap<InputMethodInfo, List<InputMethodSubtype>>();
9624e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        for (InputMethodInfo imi: mSettings.getEnabledInputMethodListLocked()) {
963bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            enabledInputMethodAndSubtypes.put(
964bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                    imi, getEnabledInputMethodSubtypeListLocked(imi, true));
965bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        }
966bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        return enabledInputMethodAndSubtypes;
967bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok    }
968bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok
969bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok    public List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(InputMethodInfo imi,
970bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            boolean allowsImplicitlySelectedSubtypes) {
971bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        if (imi == null && mCurMethodId != null) {
972bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            imi = mMethodMap.get(mCurMethodId);
973bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        }
9747265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        List<InputMethodSubtype> enabledSubtypes =
975bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                mSettings.getEnabledInputMethodSubtypeListLocked(imi);
9767265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        if (allowsImplicitlySelectedSubtypes && enabledSubtypes.isEmpty()) {
977a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            enabledSubtypes = getImplicitlyApplicableSubtypesLocked(mRes, imi);
978bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        }
9797265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        return InputMethodSubtype.sort(mContext, 0, imi, enabledSubtypes);
980bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok    }
981bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok
982e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
98316331c8a1d33defccc5cbb18694def79196c921bsatok    public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
98416331c8a1d33defccc5cbb18694def79196c921bsatok            boolean allowsImplicitlySelectedSubtypes) {
9854e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // TODO: Make this work even for non-current users?
9864e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
9874e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return Collections.emptyList();
9884e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
98967ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok        synchronized (mMethodMap) {
990bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            return getEnabledInputMethodSubtypeListLocked(imi, allowsImplicitlySelectedSubtypes);
99167ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok        }
99267ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok    }
99367ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok
994e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addClient(IInputMethodClient client,
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            IInputContext inputContext, int uid, int pid) {
9974e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
9984e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
9994e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClients.put(client.asBinder(), new ClientState(client,
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    inputContext, uid, pid));
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1005ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1006e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void removeClient(IInputMethodClient client) {
10084e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
10094e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
10104e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClients.remove(client.asBinder());
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1015ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void executeOrSendMessage(IInterface target, Message msg) {
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         if (target.asBinder() instanceof Binder) {
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             mCaller.sendMessage(msg);
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         } else {
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             handleMessage(msg);
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             msg.recycle();
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         }
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1024ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1025b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    void unbindCurrentClientLocked() {
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurClient != null) {
10278a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client = "
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + mCurClient.client.asBinder());
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mBoundToMethod) {
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBoundToMethod = false;
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurMethod != null) {
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            MSG_UNBIND_INPUT, mCurMethod));
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1036a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn
1037a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
1038a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                    MSG_SET_ACTIVE, 0, mCurClient));
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurClient.sessionRequested = false;
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurClient = null;
1043ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1044105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            hideInputMethodMenuLocked();
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1047ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getImeShowFlags() {
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int flags = 0;
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mShowForced) {
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags |= InputMethod.SHOW_FORCED
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    | InputMethod.SHOW_EXPLICIT;
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (mShowExplicitlyRequested) {
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags |= InputMethod.SHOW_EXPLICIT;
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return flags;
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1058ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getAppShowFlags() {
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int flags = 0;
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mShowForced) {
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags |= InputMethodManager.SHOW_FORCED;
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (!mShowExplicitlyRequested) {
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags |= InputMethodManager.SHOW_IMPLICIT;
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return flags;
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1068ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
10697663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn    InputBindResult attachNewInputLocked(boolean initial) {
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mBoundToMethod) {
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mBoundToMethod = true;
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final SessionState session = mCurClient.curSession;
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (initial) {
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            executeOrSendMessage(session.method, mCaller.obtainMessageOOO(
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MSG_START_INPUT, session, mCurInputContext, mCurAttribute));
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            executeOrSendMessage(session.method, mCaller.obtainMessageOOO(
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MSG_RESTART_INPUT, session, mCurInputContext, mCurAttribute));
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mShowRequested) {
10848a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
10854df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            showCurrentInputLocked(getAppShowFlags(), null);
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10877663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn        return new InputBindResult(session.session, mCurId, mCurSeq);
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1089ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    InputBindResult startInputLocked(IInputMethodClient client,
10917663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn            IInputContext inputContext, EditorInfo attribute, int controlFlags) {
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // If no method is currently selected, do nothing.
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurMethodId == null) {
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mNoBinding;
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1096ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ClientState cs = mClients.get(client.asBinder());
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (cs == null) {
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("unknown client "
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + client.asBinder());
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1102ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mIWindowManager.inputMethodClientHasFocus(cs.client)) {
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Check with the window manager to make sure this client actually
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // has a window with focus.  If not, reject.  This is thread safe
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // because if the focus changes some time before or after, the
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // next client receiving focus that has any interest in input will
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // be calling through here after that change happens.
11108a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Starting input on non-focused client " + cs.client
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (RemoteException e) {
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1116ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11177663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn        return startInputUncheckedLocked(cs, inputContext, attribute, controlFlags);
11187663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn    }
11197663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn
11207663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn    InputBindResult startInputUncheckedLocked(ClientState cs,
11217663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn            IInputContext inputContext, EditorInfo attribute, int controlFlags) {
11227663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn        // If no method is currently selected, do nothing.
11237663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn        if (mCurMethodId == null) {
11247663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn            return mNoBinding;
11257663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn        }
11267663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurClient != cs) {
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If the client is changing, we need to switch over to the new
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // one.
1130b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            unbindCurrentClientLocked();
11318a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG, "switching to client: client = "
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + cs.client.asBinder());
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If the screen is on, inform the new client it is active
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mScreenOn) {
1136a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                executeOrSendMessage(cs.client, mCaller.obtainMessageIO(
1137a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                        MSG_SET_ACTIVE, mScreenOn ? 1 : 0, cs));
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1140ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Bump up the sequence for this client and attach it.
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurSeq++;
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurSeq <= 0) mCurSeq = 1;
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurClient = cs;
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurInputContext = inputContext;
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurAttribute = attribute;
1147ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check if the input method is changing.
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurId != null && mCurId.equals(mCurMethodId)) {
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (cs.curSession != null) {
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Fast case: if we are already connected to the input method,
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // then just return it.
11537663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                return attachNewInputLocked(
11547663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        (controlFlags&InputMethodManager.CONTROL_START_INITIAL) != 0);
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mHaveConnection) {
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurMethod != null) {
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!cs.sessionRequested) {
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        cs.sessionRequested = true;
11608a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                        if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                MSG_CREATE_SESSION, mCurMethod,
1163e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard                                new MethodCallback(mCurMethod, this)));
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Return to client, and we will get back with it when
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // we have had a session made for it.
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return new InputBindResult(null, mCurId, mCurSeq);
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (SystemClock.uptimeMillis()
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        < (mLastBindTime+TIME_TO_RECONNECT)) {
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // In this case we have connected to the service, but
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // don't yet have its interface.  If it hasn't been too
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // long since we did the connection, we'll return to
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // the client and wait to get the service interface so
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // we can report back.  If it has been too long, we want
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // to fall through so we can try a disconnect/reconnect
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // to see if we can get back in touch with the service.
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return new InputBindResult(null, mCurId, mCurSeq);
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
1179ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker                    EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
1180ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker                            mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1184ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1185a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        return startInputInnerLocked();
1186a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn    }
1187ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1188a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn    InputBindResult startInputInnerLocked() {
1189a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        if (mCurMethodId == null) {
1190a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            return mNoBinding;
1191a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        }
1192ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1193a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        if (!mSystemReady) {
1194a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            // If the system is not yet ready, we shouldn't be running third
1195a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            // party code.
1196cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn            return new InputBindResult(null, mCurMethodId, mCurSeq);
1197a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        }
1198ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        InputMethodInfo info = mMethodMap.get(mCurMethodId);
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (info == null) {
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1203ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1204b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        unbindCurrentMethodLocked(false);
1205ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurIntent.setComponent(info.getComponent());
1208dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackborn        mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
1209dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackborn                com.android.internal.R.string.input_method_binding_label);
1210dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackborn        mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
1211dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackborn                mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
12124e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (bindCurrentInputMethodService(mCurIntent, this, Context.BIND_AUTO_CREATE
12132c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn                | Context.BIND_NOT_VISIBLE)) {
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLastBindTime = SystemClock.uptimeMillis();
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHaveConnection = true;
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurId = info.getId();
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurToken = new Binder();
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
12198a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurToken);
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mIWindowManager.addWindowToken(mCurToken,
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        WindowManager.LayoutParams.TYPE_INPUT_METHOD);
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new InputBindResult(null, mCurId, mCurSeq);
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurIntent = null;
12278a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            Slog.w(TAG, "Failure connecting to input method service: "
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + mCurIntent);
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1232ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1233e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public InputBindResult startInput(IInputMethodClient client,
12357663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn            IInputContext inputContext, EditorInfo attribute, int controlFlags) {
12364e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
12374e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return null;
12384e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final long ident = Binder.clearCallingIdentity();
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
12427663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                return startInputLocked(client, inputContext, attribute, controlFlags);
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Binder.restoreCallingIdentity(ident);
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1248ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1249e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void finishInput(IInputMethodClient client) {
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1252ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1253e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onServiceConnected(ComponentName name, IBinder service) {
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mCurMethod = IInputMethod.Stub.asInterface(service);
1258cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                if (mCurToken == null) {
12598a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.w(TAG, "Service connected without a token!");
1260cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                    unbindCurrentMethodLocked(false);
1261cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                    return;
1262cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                }
12638a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
1264cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
1265cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                        MSG_ATTACH_TOKEN, mCurMethod, mCurToken));
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient != null) {
12678a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.v(TAG, "Creating first session while with client "
1268cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                            + mCurClient);
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
1270cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                            MSG_CREATE_SESSION, mCurMethod,
1271e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard                            new MethodCallback(mCurMethod, this)));
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void onSessionCreated(IInputMethod method, IInputMethodSession session) {
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mCurMethod != null && method != null
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && mCurMethod.asBinder() == method.asBinder()) {
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient != null) {
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCurClient.curSession = new SessionState(mCurClient,
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            method, session);
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCurClient.sessionRequested = false;
12857663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                    InputBindResult res = attachNewInputLocked(true);
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (res.method != null) {
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                MSG_BIND_METHOD, mCurClient.client, res));
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1294ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1295b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    void unbindCurrentMethodLocked(boolean reportToClient) {
12962c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn        if (mVisibleBound) {
12972c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn            mContext.unbindService(mVisibleConnection);
12982c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn            mVisibleBound = false;
12992c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn        }
13002c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn
1301b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        if (mHaveConnection) {
1302b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            mContext.unbindService(this);
1303b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            mHaveConnection = false;
1304b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        }
1305ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1306b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        if (mCurToken != null) {
1307b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            try {
13088a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Removing window token: " + mCurToken);
1309e0a99414bd3737ad976bf4a040c184bebd8e2e3dsatok                if ((mImeWindowVis & InputMethodService.IME_ACTIVE) != 0) {
1310e0a99414bd3737ad976bf4a040c184bebd8e2e3dsatok                    // The current IME is shown. Hence an IME switch (transition) is happening.
1311e0a99414bd3737ad976bf4a040c184bebd8e2e3dsatok                    mWindowManagerService.saveLastInputMethodWindowForTransition();
1312e0a99414bd3737ad976bf4a040c184bebd8e2e3dsatok                }
1313b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                mIWindowManager.removeWindowToken(mCurToken);
1314b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            } catch (RemoteException e) {
1315b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            }
1316b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            mCurToken = null;
1317b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        }
1318ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1319105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mCurId = null;
1320b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        clearCurMethodLocked();
1321ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1322b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        if (reportToClient && mCurClient != null) {
1323b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
1324b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
1325b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        }
1326b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    }
1327b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
13280c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor    private void finishSession(SessionState sessionState) {
13290c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor        if (sessionState != null && sessionState.session != null) {
13300c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            try {
13310c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor                sessionState.session.finishSession();
13320c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            } catch (RemoteException e) {
13339d0f6dfdc1ac0b9374acf51572f273e9c9bbc9f9Jean-Baptiste Queru                Slog.w(TAG, "Session failed to close due to remote exception", e);
133415452a487a4c0274f4217cd060aa54446f30a8f3satok                setImeWindowVisibilityStatusHiddenLocked();
13350c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            }
13360c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor        }
13370c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor    }
1338ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1339b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    void clearCurMethodLocked() {
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurMethod != null) {
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (ClientState cs : mClients.values()) {
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                cs.sessionRequested = false;
13430c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor                finishSession(cs.curSession);
13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                cs.curSession = null;
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13460c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor
13470c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            finishSession(mEnabledSession);
13480c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            mEnabledSession = null;
13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurMethod = null;
13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1351661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn        if (mStatusBar != null) {
1352661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn            mStatusBar.setIconVisibility("ime", false);
1353661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn        }
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1355ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1356e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onServiceDisconnected(ComponentName name) {
13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
13598a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG, "Service disconnected: " + name
13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mCurIntent=" + mCurIntent);
13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mCurMethod != null && mCurIntent != null
13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && name.equals(mCurIntent.getComponent())) {
1363b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                clearCurMethodLocked();
13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // We consider this to be a new bind attempt, since the system
13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // should now try to restart the service for us.
13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLastBindTime = SystemClock.uptimeMillis();
13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mShowRequested = mInputShown;
13689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mInputShown = false;
13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient != null) {
13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1377f9f01008624e2d28c15a90d942fa36f98c8c967dsatok    @Override
13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void updateStatusIcon(IBinder token, String packageName, int iconId) {
1379cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn        int uid = Binder.getCallingUid();
13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long ident = Binder.clearCallingIdentity();
13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (token == null || mCurToken != token) {
1383cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                Slog.w(TAG, "Ignoring setInputMethod of uid " + uid + " token: " + token);
13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1386ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (iconId == 0) {
13898a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
1390661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    if (mStatusBar != null) {
1391661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                        mStatusBar.setIconVisibility("ime", false);
1392661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    }
13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (packageName != null) {
13948a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
13956179ea3196e9306d3f14361fe9ef14191b1edba6Svetoslav Ganov                    CharSequence contentDescription = null;
13966179ea3196e9306d3f14361fe9ef14191b1edba6Svetoslav Ganov                    try {
13974e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        // Use PackageManager to load label
13984e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        final PackageManager packageManager = mContext.getPackageManager();
13996179ea3196e9306d3f14361fe9ef14191b1edba6Svetoslav Ganov                        contentDescription = packageManager.getApplicationLabel(
14004e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                mIPackageManager.getApplicationInfo(packageName, 0,
14014e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                        mSettings.getCurrentUserId()));
14024e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    } catch (RemoteException e) {
14036179ea3196e9306d3f14361fe9ef14191b1edba6Svetoslav Ganov                        /* ignore */
14046179ea3196e9306d3f14361fe9ef14191b1edba6Svetoslav Ganov                    }
1405661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    if (mStatusBar != null) {
1406661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                        mStatusBar.setIcon("ime", packageName, iconId, 0,
1407661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                                contentDescription  != null
1408661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                                        ? contentDescription.toString() : null);
1409661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                        mStatusBar.setIconVisibility("ime", true);
1410661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    }
14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
14149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14187cfc0ed21a3fafabafb40b38a8589808ad1517afsatok    private boolean needsToShowImeSwitchOngoingNotification() {
14197cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        if (!mShowOngoingImeSwitcherForPhones) return false;
14202c93efc9eb188532472edc9e0c3e1ab8121aa20dsatok        if (isScreenLocked()) return false;
14217cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        synchronized (mMethodMap) {
14227cfc0ed21a3fafabafb40b38a8589808ad1517afsatok            List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
14237cfc0ed21a3fafabafb40b38a8589808ad1517afsatok            final int N = imis.size();
1424b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            if (N > 2) return true;
1425b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            if (N < 1) return false;
1426b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            int nonAuxCount = 0;
1427b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            int auxCount = 0;
1428b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            InputMethodSubtype nonAuxSubtype = null;
1429b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            InputMethodSubtype auxSubtype = null;
14307cfc0ed21a3fafabafb40b38a8589808ad1517afsatok            for(int i = 0; i < N; ++i) {
14317cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                final InputMethodInfo imi = imis.get(i);
14327cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                final List<InputMethodSubtype> subtypes = getEnabledInputMethodSubtypeListLocked(
14337cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                        imi, true);
14347cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                final int subtypeCount = subtypes.size();
14357cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                if (subtypeCount == 0) {
1436b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                    ++nonAuxCount;
14377cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                } else {
14387cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                    for (int j = 0; j < subtypeCount; ++j) {
1439b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                        final InputMethodSubtype subtype = subtypes.get(j);
1440b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                        if (!subtype.isAuxiliary()) {
1441b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                            ++nonAuxCount;
1442b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                            nonAuxSubtype = subtype;
1443b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                        } else {
1444b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                            ++auxCount;
1445b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                            auxSubtype = subtype;
14467cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                        }
14477cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                    }
14487cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                }
14497cfc0ed21a3fafabafb40b38a8589808ad1517afsatok            }
1450b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            if (nonAuxCount > 1 || auxCount > 1) {
1451b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                return true;
1452b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            } else if (nonAuxCount == 1 && auxCount == 1) {
1453b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                if (nonAuxSubtype != null && auxSubtype != null
14549747f8977c55013e656a1e666a1647bb331954cesatok                        && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
14559747f8977c55013e656a1e666a1647bb331954cesatok                                || auxSubtype.overridesImplicitlyEnabledSubtype()
14569747f8977c55013e656a1e666a1647bb331954cesatok                                || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
1457b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                        && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
1458b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                    return false;
1459b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                }
1460b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                return true;
1461b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            }
1462b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            return false;
14637cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        }
14647cfc0ed21a3fafabafb40b38a8589808ad1517afsatok    }
14657cfc0ed21a3fafabafb40b38a8589808ad1517afsatok
14664e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    // Caution! This method is called in this class. Handle multi-user carefully
1467dbf2950781ab0c4c0fc4ad9bd71b13c55ae6f471satok    @SuppressWarnings("deprecation")
1468f9f01008624e2d28c15a90d942fa36f98c8c967dsatok    @Override
1469857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato    public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
14704e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final long ident = Binder.clearCallingIdentity();
147106487a58be22b100daf3f950b9a1d25c3ea42aa2satok        try {
147206487a58be22b100daf3f950b9a1d25c3ea42aa2satok            if (token == null || mCurToken != token) {
14734e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                int uid = Binder.getCallingUid();
1474857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                Slog.w(TAG, "Ignoring setImeWindowStatus of uid " + uid + " token: " + token);
147506487a58be22b100daf3f950b9a1d25c3ea42aa2satok                return;
147606487a58be22b100daf3f950b9a1d25c3ea42aa2satok            }
147706487a58be22b100daf3f950b9a1d25c3ea42aa2satok
147806487a58be22b100daf3f950b9a1d25c3ea42aa2satok            synchronized (mMethodMap) {
1479857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                mImeWindowVis = vis;
1480857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                mBackDisposition = backDisposition;
1481661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                if (mStatusBar != null) {
1482661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    mStatusBar.setImeWindowStatus(token, vis, backDisposition);
1483661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                }
14847cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                final boolean iconVisibility = (vis & InputMethodService.IME_ACTIVE) != 0;
14855bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
14865bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                if (imi != null && iconVisibility && needsToShowImeSwitchOngoingNotification()) {
14874e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    // Used to load label
14887cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                    final PackageManager pm = mContext.getPackageManager();
14897cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                    final CharSequence title = mRes.getText(
14907cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                            com.android.internal.R.string.select_input_method);
14915bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                    final CharSequence imiLabel = imi.loadLabel(pm);
14925bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                    final CharSequence summary = mCurrentSubtype != null
14935bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                            ? TextUtils.concat(mCurrentSubtype.getDisplayName(mContext,
14945bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                                        imi.getPackageName(), imi.getServiceInfo().applicationInfo),
14955bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                                                (TextUtils.isEmpty(imiLabel) ?
149605dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                                                        "" : " - " + imiLabel))
14975bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                            : imiLabel;
14985bc8e732bd831a308a5bc1720b0e4c9300d32f67satok
14997cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                    mImeSwitcherNotification.setLatestEventInfo(
15005bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                            mContext, title, summary, mImeSwitchPendingIntent);
1501661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    if (mNotificationManager != null) {
1502135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        if (DEBUG) {
1503135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                            Slog.d(TAG, "--- show notification: label =  " + imiLabel
1504135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                                    + ", summary = " + summary);
1505135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        }
1506135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        mNotificationManager.notifyAsUser(null,
1507661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                                com.android.internal.R.string.select_input_method,
1508135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                                mImeSwitcherNotification, UserHandle.ALL);
1509661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                        mNotificationShown = true;
1510661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    }
15117cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                } else {
1512661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    if (mNotificationShown && mNotificationManager != null) {
1513135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        if (DEBUG) {
1514135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                            Slog.d(TAG, "--- hide notification");
1515135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        }
1516135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        mNotificationManager.cancelAsUser(null,
1517135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                                com.android.internal.R.string.select_input_method, UserHandle.ALL);
15187cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                        mNotificationShown = false;
15197cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                    }
15207cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                }
152106487a58be22b100daf3f950b9a1d25c3ea42aa2satok            }
152206487a58be22b100daf3f950b9a1d25c3ea42aa2satok        } finally {
152306487a58be22b100daf3f950b9a1d25c3ea42aa2satok            Binder.restoreCallingIdentity(ident);
152406487a58be22b100daf3f950b9a1d25c3ea42aa2satok        }
152506487a58be22b100daf3f950b9a1d25c3ea42aa2satok    }
152606487a58be22b100daf3f950b9a1d25c3ea42aa2satok
1527e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
1528f9f01008624e2d28c15a90d942fa36f98c8c967dsatok    public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) {
15294e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
15304e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
15314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
1532f9f01008624e2d28c15a90d942fa36f98c8c967dsatok        synchronized (mMethodMap) {
1533f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
1534f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            for (int i = 0; i < spans.length; ++i) {
1535f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                SuggestionSpan ss = spans[i];
153642c5a1666c4e576ccd5974233513100aad2c1534satok                if (!TextUtils.isEmpty(ss.getNotificationTargetClassName())) {
1537f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                    mSecureSuggestionSpans.put(ss, currentImi);
153842c5a1666c4e576ccd5974233513100aad2c1534satok                    final InputMethodInfo targetImi = mSecureSuggestionSpans.get(ss);
1539f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                }
1540f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            }
1541f9f01008624e2d28c15a90d942fa36f98c8c967dsatok        }
1542f9f01008624e2d28c15a90d942fa36f98c8c967dsatok    }
1543f9f01008624e2d28c15a90d942fa36f98c8c967dsatok
1544e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
1545f9f01008624e2d28c15a90d942fa36f98c8c967dsatok    public boolean notifySuggestionPicked(SuggestionSpan span, String originalString, int index) {
15464e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
15474e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
15484e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
1549f9f01008624e2d28c15a90d942fa36f98c8c967dsatok        synchronized (mMethodMap) {
1550f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            final InputMethodInfo targetImi = mSecureSuggestionSpans.get(span);
1551f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            // TODO: Do not send the intent if the process of the targetImi is already dead.
1552f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            if (targetImi != null) {
1553f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                final String[] suggestions = span.getSuggestions();
1554f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                if (index < 0 || index >= suggestions.length) return false;
155542c5a1666c4e576ccd5974233513100aad2c1534satok                final String className = span.getNotificationTargetClassName();
1556f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                final Intent intent = new Intent();
1557f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                // Ensures that only a class in the original IME package will receive the
1558f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                // notification.
155942c5a1666c4e576ccd5974233513100aad2c1534satok                intent.setClassName(targetImi.getPackageName(), className);
1560f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                intent.setAction(SuggestionSpan.ACTION_SUGGESTION_PICKED);
1561f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_BEFORE, originalString);
1562f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_AFTER, suggestions[index]);
1563f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_HASHCODE, span.hashCode());
1564f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                mContext.sendBroadcast(intent);
1565f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                return true;
1566f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            }
1567f9f01008624e2d28c15a90d942fa36f98c8c967dsatok        }
1568f9f01008624e2d28c15a90d942fa36f98c8c967dsatok        return false;
1569f9f01008624e2d28c15a90d942fa36f98c8c967dsatok    }
1570f9f01008624e2d28c15a90d942fa36f98c8c967dsatok
15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void updateFromSettingsLocked() {
1572b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and
1573b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        // ENABLED_INPUT_METHODS is taking care of keeping them correctly in
1574b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        // sync, so we will never have a DEFAULT_INPUT_METHOD that is not
1575b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        // enabled.
15764e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        String id = mSettings.getSelectedInputMethod();
157703eb319a3a7fe6fe9ab9eba6fc1f727285850906satok        // There is no input method selected, try to choose new applicable input method.
157803eb319a3a7fe6fe9ab9eba6fc1f727285850906satok        if (TextUtils.isEmpty(id) && chooseNewDefaultIMELocked()) {
15794e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            id = mSettings.getSelectedInputMethod();
158003eb319a3a7fe6fe9ab9eba6fc1f727285850906satok        }
158103eb319a3a7fe6fe9ab9eba6fc1f727285850906satok        if (!TextUtils.isEmpty(id)) {
15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
1583ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                setInputMethodLocked(id, getSelectedInputMethodSubtypeId(id));
15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IllegalArgumentException e) {
15858a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Unknown input method from prefs: " + id, e);
1586105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                mCurMethodId = null;
1587b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                unbindCurrentMethodLocked(true);
15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1589f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            mShortcutInputMethodsAndSubtypes.clear();
1590b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        } else {
1591b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            // There is no longer an input method set, so stop any current one.
1592105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mCurMethodId = null;
1593b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            unbindCurrentMethodLocked(true);
15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1596ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1597ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    /* package */ void setInputMethodLocked(String id, int subtypeId) {
15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        InputMethodInfo info = mMethodMap.get(id);
15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (info == null) {
1600913a8925c07e854a80bf5df87561f290d3a56d61satok            throw new IllegalArgumentException("Unknown id: " + id);
16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1602ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1603d81e950265356c81276b73da68a535ffa48d72f0satok        // See if we need to notify a subtype change within the same IME.
16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (id.equals(mCurMethodId)) {
1605d81e950265356c81276b73da68a535ffa48d72f0satok            final int subtypeCount = info.getSubtypeCount();
1606d81e950265356c81276b73da68a535ffa48d72f0satok            if (subtypeCount <= 0) {
1607d81e950265356c81276b73da68a535ffa48d72f0satok                return;
1608d81e950265356c81276b73da68a535ffa48d72f0satok            }
1609d81e950265356c81276b73da68a535ffa48d72f0satok            final InputMethodSubtype oldSubtype = mCurrentSubtype;
1610d81e950265356c81276b73da68a535ffa48d72f0satok            final InputMethodSubtype newSubtype;
1611d81e950265356c81276b73da68a535ffa48d72f0satok            if (subtypeId >= 0 && subtypeId < subtypeCount) {
1612d81e950265356c81276b73da68a535ffa48d72f0satok                newSubtype = info.getSubtypeAt(subtypeId);
1613d81e950265356c81276b73da68a535ffa48d72f0satok            } else {
1614d81e950265356c81276b73da68a535ffa48d72f0satok                // If subtype is null, try to find the most applicable one from
1615d81e950265356c81276b73da68a535ffa48d72f0satok                // getCurrentInputMethodSubtype.
16164e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                newSubtype = getCurrentInputMethodSubtypeLocked();
1617d81e950265356c81276b73da68a535ffa48d72f0satok            }
1618d81e950265356c81276b73da68a535ffa48d72f0satok            if (newSubtype == null || oldSubtype == null) {
1619d81e950265356c81276b73da68a535ffa48d72f0satok                Slog.w(TAG, "Illegal subtype state: old subtype = " + oldSubtype
1620d81e950265356c81276b73da68a535ffa48d72f0satok                        + ", new subtype = " + newSubtype);
1621d81e950265356c81276b73da68a535ffa48d72f0satok                return;
1622d81e950265356c81276b73da68a535ffa48d72f0satok            }
1623d81e950265356c81276b73da68a535ffa48d72f0satok            if (newSubtype != oldSubtype) {
1624d81e950265356c81276b73da68a535ffa48d72f0satok                setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
1625d81e950265356c81276b73da68a535ffa48d72f0satok                if (mCurMethod != null) {
1626d81e950265356c81276b73da68a535ffa48d72f0satok                    try {
1627d81e950265356c81276b73da68a535ffa48d72f0satok                        refreshImeWindowVisibilityLocked();
1628d81e950265356c81276b73da68a535ffa48d72f0satok                        mCurMethod.changeInputMethodSubtype(newSubtype);
1629d81e950265356c81276b73da68a535ffa48d72f0satok                    } catch (RemoteException e) {
1630d81e950265356c81276b73da68a535ffa48d72f0satok                        Slog.w(TAG, "Failed to call changeInputMethodSubtype");
1631ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    }
1632ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                }
1633ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            }
16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1636ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1637d81e950265356c81276b73da68a535ffa48d72f0satok        // Changing to a different IME.
16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long ident = Binder.clearCallingIdentity();
16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
1640ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            // Set a subtype to this input method.
1641ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            // subtypeId the name of a subtype which will be set.
1642723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            setSelectedInputMethodAndSubtypeLocked(info, subtypeId, false);
1643723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
1644723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // because mCurMethodId is stored as a history in
1645723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // setSelectedInputMethodAndSubtypeLocked().
1646723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mCurMethodId = id;
16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (ActivityManagerNative.isSystemReady()) {
16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
16501c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                intent.putExtra("input_method_id", id);
16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mContext.sendBroadcast(intent);
16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1654b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            unbindCurrentClientLocked();
16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1659ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
166042c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
16614df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    public boolean showSoftInput(IInputMethodClient client, int flags,
16624df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            ResultReceiver resultReceiver) {
16634e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
16644e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
16654e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
1666cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn        int uid = Binder.getCallingUid();
16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long ident = Binder.clearCallingIdentity();
16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient == null || client == null
16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        || mCurClient.client.asBinder() != client.asBinder()) {
16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // We need to check if this is the current client with
16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // focus in the window manager, to allow this call to
16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // be made before input is started in it.
16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (!mIWindowManager.inputMethodClientHasFocus(client)) {
1677cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                            Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
16784df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            return false;
16799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (RemoteException e) {
16814df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                        return false;
16829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
16839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1684ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
16858a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
16864df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                return showCurrentInputLocked(flags, resultReceiver);
16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1692ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
16934df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    boolean showCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mShowRequested = true;
16959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mShowExplicitlyRequested = true;
16979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
16999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mShowExplicitlyRequested = true;
17009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mShowForced = true;
17019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1702ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1703cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn        if (!mSystemReady) {
1704cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn            return false;
1705cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn        }
1706ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
17074df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        boolean res = false;
17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurMethod != null) {
17094df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
17104df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod,
17114df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    resultReceiver));
17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mInputShown = true;
17132c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn            if (mHaveConnection && !mVisibleBound) {
17144e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                bindCurrentInputMethodService(
17154e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        mCurIntent, mVisibleConnection, Context.BIND_AUTO_CREATE);
17162c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn                mVisibleBound = true;
17172c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn            }
17184df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            res = true;
17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (mHaveConnection && SystemClock.uptimeMillis()
172059b424c3b6121c9579fc5efcc785ba084072a5casatok                >= (mLastBindTime+TIME_TO_RECONNECT)) {
17219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // The client has asked to have the input method shown, but
17229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // we have been sitting here too long with a connection to the
17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // service and no interface received, so let's disconnect/connect
17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // to try to prod things along.
1725ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker            EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId,
17269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SystemClock.uptimeMillis()-mLastBindTime,1);
172759b424c3b6121c9579fc5efcc785ba084072a5casatok            Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()");
17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.unbindService(this);
17294e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            bindCurrentInputMethodService(mCurIntent, this, Context.BIND_AUTO_CREATE
17302c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn                    | Context.BIND_NOT_VISIBLE);
17314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        } else {
17324e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
17334e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "Can't show input: connection = " + mHaveConnection + ", time = "
17344e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        + ((mLastBindTime+TIME_TO_RECONNECT) - SystemClock.uptimeMillis()));
17354e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1737ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
17384df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        return res;
17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1740ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
174142c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
17424df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    public boolean hideSoftInput(IInputMethodClient client, int flags,
17434df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            ResultReceiver resultReceiver) {
17444e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
17454e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
17464e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
1747cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn        int uid = Binder.getCallingUid();
17489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long ident = Binder.clearCallingIdentity();
17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
17509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
17519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient == null || client == null
17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        || mCurClient.client.asBinder() != client.asBinder()) {
17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
17549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // We need to check if this is the current client with
17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // focus in the window manager, to allow this call to
17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // be made before input is started in it.
17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (!mIWindowManager.inputMethodClientHasFocus(client)) {
1758cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                            if (DEBUG) Slog.w(TAG, "Ignoring hideSoftInput of uid "
1759cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                                    + uid + ": " + client);
176015452a487a4c0274f4217cd060aa54446f30a8f3satok                            setImeWindowVisibilityStatusHiddenLocked();
17614df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            return false;
17629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
17639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (RemoteException e) {
176415452a487a4c0274f4217cd060aa54446f30a8f3satok                        setImeWindowVisibilityStatusHiddenLocked();
17654df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                        return false;
17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1768ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
17698a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
17704df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                return hideCurrentInputLocked(flags, resultReceiver);
17719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
17739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
17749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1776ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
17774df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
17789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
17799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                && (mShowExplicitlyRequested || mShowForced)) {
17808a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG,
17819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    "Not hiding: explicit show not cancelled by non-explicit hide");
17824df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            return false;
17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
17858a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG,
17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    "Not hiding: forced show not cancelled by not-always hide");
17874df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            return false;
17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17894df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        boolean res;
17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mInputShown && mCurMethod != null) {
17914df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
17924df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    MSG_HIDE_SOFT_INPUT, mCurMethod, resultReceiver));
17934df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            res = true;
17944df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        } else {
17954df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            res = false;
17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17972c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn        if (mHaveConnection && mVisibleBound) {
17982c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn            mContext.unbindService(mVisibleConnection);
17992c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn            mVisibleBound = false;
18002c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn        }
18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mInputShown = false;
18029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mShowRequested = false;
18039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mShowExplicitlyRequested = false;
18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mShowForced = false;
18054df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        return res;
18069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1807ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
180842c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
18097663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn    public InputBindResult windowGainedFocus(IInputMethodClient client, IBinder windowToken,
18107663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn            int controlFlags, int softInputMode, int windowFlags,
18117663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn            EditorInfo attribute, IInputContext inputContext) {
18124e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
18134e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return null;
18144e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
18157663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn        InputBindResult res = null;
18169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long ident = Binder.clearCallingIdentity();
18179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
18189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
18198a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "windowGainedFocus: " + client.asBinder()
18207663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        + " controlFlags=#" + Integer.toHexString(controlFlags)
18219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + " softInputMode=#" + Integer.toHexString(softInputMode)
18227663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        + " windowFlags=#" + Integer.toHexString(windowFlags));
1823ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
18247663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                ClientState cs = mClients.get(client.asBinder());
18257663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                if (cs == null) {
18267663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                    throw new IllegalArgumentException("unknown client "
18277663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            + client.asBinder());
18287663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                }
18297663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn
18307663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                try {
18317663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                    if (!mIWindowManager.inputMethodClientHasFocus(cs.client)) {
18327663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        // Check with the window manager to make sure this client actually
18337663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        // has a window with focus.  If not, reject.  This is thread safe
18347663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        // because if the focus changes some time before or after, the
18357663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        // next client receiving focus that has any interest in input will
18367663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        // be calling through here after that change happens.
18377663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        Slog.w(TAG, "Focus gain on non-focused client " + cs.client
18387663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
18397663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        return null;
18409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
18417663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                } catch (RemoteException e) {
18429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1843ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1844b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                if (mCurFocusedWindow == windowToken) {
1845ac92087a9a1c464d4b0a58c82dae01cbaa088e89Dianne Hackborn                    Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
18463573950e0b30178dc963de3fa00aba2ebcfd552dSatoshi Kataoka                            + " attribute=" + attribute + ", token = " + windowToken);
18477663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                    if (attribute != null) {
18487663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        return startInputUncheckedLocked(cs, inputContext, attribute,
18497663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                controlFlags);
18507663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                    }
18517663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                    return null;
1852b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
1853b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                mCurFocusedWindow = windowToken;
1854ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
18557d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // Should we auto-show the IME even if the caller has not
18567d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // specified what should be done with it?
18577d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // We only do this automatically if the window can resize
18587d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // to accommodate the IME (so what the user sees will give
18597d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // them good context without input information being obscured
18607d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // by the IME) or if running on a large screen where there
18617d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // is more room for the target window + IME.
18627d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                final boolean doAutoShow =
18637d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                        (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
18647d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                                == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
18657d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                        || mRes.getConfiguration().isLayoutSizeAtLeast(
18667d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                                Configuration.SCREENLAYOUT_SIZE_LARGE);
18677663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                final boolean isTextEditor =
18687663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        (controlFlags&InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR) != 0;
18697663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn
18707663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                // We want to start input before showing the IME, but after closing
18717663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                // it.  We want to do this after closing it to help the IME disappear
18727663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                // more quickly (not get stuck behind it initializing itself for the
18737663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                // new focused input, even if its window wants to hide the IME).
18747663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                boolean didStart = false;
18757d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn
18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
18787d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                        if (!isTextEditor || !doAutoShow) {
18799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (WindowManager.LayoutParams.mayUseInputMethod(windowFlags)) {
18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                // There is no focus view, and this window will
18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                // be behind any soft input window, so hide the
18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                // soft input window if it is shown.
18838a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                                if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
18844df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                                hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
18867d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                        } else if (isTextEditor && doAutoShow && (softInputMode &
18877d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // There is a focus view, and we are navigating forward
18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // into the window, so show the input window for the user.
18907663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            // We only do this automatically if the window can resize
18917663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            // to accommodate the IME (so what the user sees will give
18927d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                            // them good context without input information being obscured
18937d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                            // by the IME) or if running on a large screen where there
18947d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                            // is more room for the target window + IME.
18958a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
18967663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            if (attribute != null) {
18977663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                res = startInputUncheckedLocked(cs, inputContext, attribute,
18987663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                        controlFlags);
18997663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                didStart = true;
19007663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            }
19014df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
19029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
19039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
19049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
19059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // Do nothing.
19069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
19079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
19089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if ((softInputMode &
19099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
19108a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
19114df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            hideCurrentInputLocked(0, null);
19129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
19139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
19149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
19158a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                        if (DEBUG) Slog.v(TAG, "Window asks to hide input");
19164df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                        hideCurrentInputLocked(0, null);
19179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
19189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
19199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if ((softInputMode &
19209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
19218a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
19227663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            if (attribute != null) {
19237663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                res = startInputUncheckedLocked(cs, inputContext, attribute,
19247663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                        controlFlags);
19257663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                didStart = true;
19267663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            }
19274df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
19289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
19299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
19309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
19318a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                        if (DEBUG) Slog.v(TAG, "Window asks to always show input");
19327663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        if (attribute != null) {
19337663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            res = startInputUncheckedLocked(cs, inputContext, attribute,
19347663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                    controlFlags);
19357663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            didStart = true;
19367663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        }
19374df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                        showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
19389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
19399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
19407663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn
19417663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                if (!didStart && attribute != null) {
19427663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                    res = startInputUncheckedLocked(cs, inputContext, attribute,
19437663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            controlFlags);
19447663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                }
19459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
19479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
19489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19497663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn
19507663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn        return res;
19519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1952ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
195342c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
19549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void showInputMethodPickerFromClient(IInputMethodClient client) {
19554e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
19564e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
19574e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
19589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
19599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mCurClient == null || client == null
19609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    || mCurClient.client.asBinder() != client.asBinder()) {
196147a44916e2fb33cf4751906386d5f5c903b28d8bsatok                Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
1962cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                        + Binder.getCallingUid() + ": " + client);
19639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1965440aab54cab106030f1edafea4dec1f9d8624f9bsatok            // Always call subtype picker, because subtype picker is a superset of input method
1966440aab54cab106030f1edafea4dec1f9d8624f9bsatok            // picker.
1967ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            mHandler.sendEmptyMessage(MSG_SHOW_IM_SUBTYPE_PICKER);
1968ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        }
1969ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
1970ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
197142c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
19729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setInputMethod(IBinder token, String id) {
19734e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
19744e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
19754e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
19762820351489537698ad153c6397edf3270455edc5satok        setInputMethodWithSubtypeId(token, id, NOT_A_SUBTYPE_ID);
19772820351489537698ad153c6397edf3270455edc5satok    }
19782820351489537698ad153c6397edf3270455edc5satok
197942c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
19802820351489537698ad153c6397edf3270455edc5satok    public void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) {
19814e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
19824e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
19834e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
19842820351489537698ad153c6397edf3270455edc5satok        synchronized (mMethodMap) {
19852820351489537698ad153c6397edf3270455edc5satok            if (subtype != null) {
19862820351489537698ad153c6397edf3270455edc5satok                setInputMethodWithSubtypeId(token, id, getSubtypeIdFromHashCode(
19872820351489537698ad153c6397edf3270455edc5satok                        mMethodMap.get(id), subtype.hashCode()));
19882820351489537698ad153c6397edf3270455edc5satok            } else {
19892820351489537698ad153c6397edf3270455edc5satok                setInputMethod(token, id);
19902820351489537698ad153c6397edf3270455edc5satok            }
19912820351489537698ad153c6397edf3270455edc5satok        }
1992ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
1993ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
199442c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
1995b416a71e56cdd50742eb897366a140775aa4cd61satok    public void showInputMethodAndSubtypeEnablerFromClient(
1996217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok            IInputMethodClient client, String inputMethodId) {
19974e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
19984e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
19994e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
2000b416a71e56cdd50742eb897366a140775aa4cd61satok        synchronized (mMethodMap) {
2001b416a71e56cdd50742eb897366a140775aa4cd61satok            if (mCurClient == null || client == null
2002b416a71e56cdd50742eb897366a140775aa4cd61satok                || mCurClient.client.asBinder() != client.asBinder()) {
2003b416a71e56cdd50742eb897366a140775aa4cd61satok                Slog.w(TAG, "Ignoring showInputMethodAndSubtypeEnablerFromClient of: " + client);
2004b416a71e56cdd50742eb897366a140775aa4cd61satok            }
20057fee71f66afef6421b92fa48e63d4bc73f5d0c27satok            executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
20067fee71f66afef6421b92fa48e63d4bc73f5d0c27satok                    MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
2007b416a71e56cdd50742eb897366a140775aa4cd61satok        }
2008b416a71e56cdd50742eb897366a140775aa4cd61satok    }
2009b416a71e56cdd50742eb897366a140775aa4cd61satok
20104fc87d61c29886c848789208c9e32ba9ac4e5dd3satok    @Override
2011735cf38b8c7f8f91ad087511e44fe79018fa61d6satok    public boolean switchToLastInputMethod(IBinder token) {
20124e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
20134e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
20144e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
2015735cf38b8c7f8f91ad087511e44fe79018fa61d6satok        synchronized (mMethodMap) {
2016c445bcd0bce630948ee029d7c70b28226f0b6c9csatok            final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
20174fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            final InputMethodInfo lastImi;
2018208d5634047111811de16fb63c43d0bc8b4fe6desatok            if (lastIme != null) {
20194fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                lastImi = mMethodMap.get(lastIme.first);
20204fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            } else {
20214fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                lastImi = null;
20224fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            }
20234fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            String targetLastImiId = null;
20244fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            int subtypeId = NOT_A_SUBTYPE_ID;
20254fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            if (lastIme != null && lastImi != null) {
20264fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                final boolean imiIdIsSame = lastImi.getId().equals(mCurMethodId);
20274fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                final int lastSubtypeHash = Integer.valueOf(lastIme.second);
20284fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                final int currentSubtypeHash = mCurrentSubtype == null ? NOT_A_SUBTYPE_ID
20294fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                        : mCurrentSubtype.hashCode();
20304fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                // If the last IME is the same as the current IME and the last subtype is not
20314fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                // defined, there is no need to switch to the last IME.
20324fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                if (!imiIdIsSame || lastSubtypeHash != currentSubtypeHash) {
20334fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                    targetLastImiId = lastIme.first;
20344fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                    subtypeId = getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
20354fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                }
20364fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            }
20374fc87d61c29886c848789208c9e32ba9ac4e5dd3satok
20384fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            if (TextUtils.isEmpty(targetLastImiId) && !canAddToLastInputMethod(mCurrentSubtype)) {
20394fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                // This is a safety net. If the currentSubtype can't be added to the history
20404fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                // and the framework couldn't find the last ime, we will make the last ime be
20414fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                // the most applicable enabled keyboard subtype of the system imes.
20424fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                final List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
20434fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                if (enabled != null) {
20444fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                    final int N = enabled.size();
20454fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                    final String locale = mCurrentSubtype == null
20464fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                            ? mRes.getConfiguration().locale.toString()
20474fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                            : mCurrentSubtype.getLocale();
20484fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                    for (int i = 0; i < N; ++i) {
20494fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                        final InputMethodInfo imi = enabled.get(i);
20504fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                        if (imi.getSubtypeCount() > 0 && isSystemIme(imi)) {
20514fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                            InputMethodSubtype keyboardSubtype =
20524fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                    findLastResortApplicableSubtypeLocked(mRes, getSubtypes(imi),
20534fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                            SUBTYPE_MODE_KEYBOARD, locale, true);
20544fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                            if (keyboardSubtype != null) {
20554fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                targetLastImiId = imi.getId();
20564fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                subtypeId = getSubtypeIdFromHashCode(
20574fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                        imi, keyboardSubtype.hashCode());
20584fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                if(keyboardSubtype.getLocale().equals(locale)) {
20594fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                    break;
20604fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                }
20614fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                            }
20624fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                        }
20634fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                    }
20644fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                }
20654fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            }
2066c445bcd0bce630948ee029d7c70b28226f0b6c9csatok
20674fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            if (!TextUtils.isEmpty(targetLastImiId)) {
2068c445bcd0bce630948ee029d7c70b28226f0b6c9csatok                if (DEBUG) {
20694fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                    Slog.d(TAG, "Switch to: " + lastImi.getId() + ", " + lastIme.second
20704fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                            + ", from: " + mCurMethodId + ", " + subtypeId);
2071735cf38b8c7f8f91ad087511e44fe79018fa61d6satok                }
20724fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                setInputMethodWithSubtypeId(token, targetLastImiId, subtypeId);
2073c445bcd0bce630948ee029d7c70b28226f0b6c9csatok                return true;
20744fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            } else {
20754fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                return false;
2076735cf38b8c7f8f91ad087511e44fe79018fa61d6satok            }
2077735cf38b8c7f8f91ad087511e44fe79018fa61d6satok        }
2078735cf38b8c7f8f91ad087511e44fe79018fa61d6satok    }
2079735cf38b8c7f8f91ad087511e44fe79018fa61d6satok
2080e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
2081688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok    public boolean switchToNextInputMethod(IBinder token, boolean onlyCurrentIme) {
20824e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
20834e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
20844e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
2085688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        synchronized (mMethodMap) {
2086688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            final ImeSubtypeListItem nextSubtype = mImListManager.getNextInputMethod(
2087688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype);
2088688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            if (nextSubtype == null) {
2089688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                return false;
2090688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            }
2091688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            setInputMethodWithSubtypeId(token, nextSubtype.mImi.getId(), nextSubtype.mSubtypeId);
2092688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            return true;
2093688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        }
2094688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok    }
2095688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok
2096688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok    @Override
209768f1b78b7b9139a0e34285ff641a664e664a14b8satok    public InputMethodSubtype getLastInputMethodSubtype() {
20984e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
20994e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return null;
21004e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
210168f1b78b7b9139a0e34285ff641a664e664a14b8satok        synchronized (mMethodMap) {
210268f1b78b7b9139a0e34285ff641a664e664a14b8satok            final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
210368f1b78b7b9139a0e34285ff641a664e664a14b8satok            // TODO: Handle the case of the last IME with no subtypes
210468f1b78b7b9139a0e34285ff641a664e664a14b8satok            if (lastIme == null || TextUtils.isEmpty(lastIme.first)
210568f1b78b7b9139a0e34285ff641a664e664a14b8satok                    || TextUtils.isEmpty(lastIme.second)) return null;
210668f1b78b7b9139a0e34285ff641a664e664a14b8satok            final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
210768f1b78b7b9139a0e34285ff641a664e664a14b8satok            if (lastImi == null) return null;
210868f1b78b7b9139a0e34285ff641a664e664a14b8satok            try {
210968f1b78b7b9139a0e34285ff641a664e664a14b8satok                final int lastSubtypeHash = Integer.valueOf(lastIme.second);
21100e7d7d632309409e2bc51d5317cf7a92a7541433satok                final int lastSubtypeId = getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
21110e7d7d632309409e2bc51d5317cf7a92a7541433satok                if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
21120e7d7d632309409e2bc51d5317cf7a92a7541433satok                    return null;
21130e7d7d632309409e2bc51d5317cf7a92a7541433satok                }
21140e7d7d632309409e2bc51d5317cf7a92a7541433satok                return lastImi.getSubtypeAt(lastSubtypeId);
211568f1b78b7b9139a0e34285ff641a664e664a14b8satok            } catch (NumberFormatException e) {
211668f1b78b7b9139a0e34285ff641a664e664a14b8satok                return null;
211768f1b78b7b9139a0e34285ff641a664e664a14b8satok            }
211868f1b78b7b9139a0e34285ff641a664e664a14b8satok        }
211968f1b78b7b9139a0e34285ff641a664e664a14b8satok    }
212068f1b78b7b9139a0e34285ff641a664e664a14b8satok
2121e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
2122ee5e77cafec2eae70890abdcc1646ed39b06edddsatok    public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
21234e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
21244e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
21254e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
212691e88122cf28a48fd2e2260da7d3d87dd437227asatok        // By this IPC call, only a process which shares the same uid with the IME can add
212791e88122cf28a48fd2e2260da7d3d87dd437227asatok        // additional input method subtypes to the IME.
2128ee5e77cafec2eae70890abdcc1646ed39b06edddsatok        if (TextUtils.isEmpty(imiId) || subtypes == null || subtypes.length == 0) return;
2129e7c6998e0a953ae55487d4fe122739646f9280aasatok        synchronized (mMethodMap) {
213091e88122cf28a48fd2e2260da7d3d87dd437227asatok            final InputMethodInfo imi = mMethodMap.get(imiId);
2131ee5e77cafec2eae70890abdcc1646ed39b06edddsatok            if (imi == null) return;
21324e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            final String[] packageInfos;
21334e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            try {
21344e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                packageInfos = mIPackageManager.getPackagesForUid(Binder.getCallingUid());
21354e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            } catch (RemoteException e) {
21364e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.e(TAG, "Failed to get package infos");
21374e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                return;
21384e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
213991e88122cf28a48fd2e2260da7d3d87dd437227asatok            if (packageInfos != null) {
214091e88122cf28a48fd2e2260da7d3d87dd437227asatok                final int packageNum = packageInfos.length;
214191e88122cf28a48fd2e2260da7d3d87dd437227asatok                for (int i = 0; i < packageNum; ++i) {
214291e88122cf28a48fd2e2260da7d3d87dd437227asatok                    if (packageInfos[i].equals(imi.getPackageName())) {
214391e88122cf28a48fd2e2260da7d3d87dd437227asatok                        mFileManager.addInputMethodSubtypes(imi, subtypes);
2144c593380d1bccbfbd45c404954b2670b65acc287fsatok                        final long ident = Binder.clearCallingIdentity();
2145c593380d1bccbfbd45c404954b2670b65acc287fsatok                        try {
2146c593380d1bccbfbd45c404954b2670b65acc287fsatok                            buildInputMethodListLocked(mMethodList, mMethodMap);
2147c593380d1bccbfbd45c404954b2670b65acc287fsatok                        } finally {
2148c593380d1bccbfbd45c404954b2670b65acc287fsatok                            Binder.restoreCallingIdentity(ident);
2149c593380d1bccbfbd45c404954b2670b65acc287fsatok                        }
2150ee5e77cafec2eae70890abdcc1646ed39b06edddsatok                        return;
215191e88122cf28a48fd2e2260da7d3d87dd437227asatok                    }
215291e88122cf28a48fd2e2260da7d3d87dd437227asatok                }
215391e88122cf28a48fd2e2260da7d3d87dd437227asatok            }
2154e7c6998e0a953ae55487d4fe122739646f9280aasatok        }
2155ee5e77cafec2eae70890abdcc1646ed39b06edddsatok        return;
2156e7c6998e0a953ae55487d4fe122739646f9280aasatok    }
2157e7c6998e0a953ae55487d4fe122739646f9280aasatok
21582820351489537698ad153c6397edf3270455edc5satok    private void setInputMethodWithSubtypeId(IBinder token, String id, int subtypeId) {
21599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
21609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (token == null) {
21619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mContext.checkCallingOrSelfPermission(
21629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        android.Manifest.permission.WRITE_SECURE_SETTINGS)
21639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        != PackageManager.PERMISSION_GRANTED) {
21649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    throw new SecurityException(
21659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            "Using null token requires permission "
21669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            + android.Manifest.permission.WRITE_SECURE_SETTINGS);
21679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
21689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (mCurToken != token) {
2169cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
2170cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                        + " token: " + token);
21719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
21729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2174c593380d1bccbfbd45c404954b2670b65acc287fsatok            final long ident = Binder.clearCallingIdentity();
21759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
2176ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                setInputMethodLocked(id, subtypeId);
21779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
21789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Binder.restoreCallingIdentity(ident);
21799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
218342c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
21849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void hideMySoftInput(IBinder token, int flags) {
21854e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
21864e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
21874e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
21889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
21899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (token == null || mCurToken != token) {
2190cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                if (DEBUG) Slog.w(TAG, "Ignoring hideInputMethod of uid "
2191cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                        + Binder.getCallingUid() + " token: " + token);
21929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
21939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long ident = Binder.clearCallingIdentity();
21959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
21964df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                hideCurrentInputLocked(flags, null);
21974df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            } finally {
21984df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                Binder.restoreCallingIdentity(ident);
21994df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            }
22004df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        }
22014df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    }
2202ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
220342c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
22044df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    public void showMySoftInput(IBinder token, int flags) {
22054e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
22064e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
22074e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
22084df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        synchronized (mMethodMap) {
22094df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            if (token == null || mCurToken != token) {
2210cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                Slog.w(TAG, "Ignoring showMySoftInput of uid "
2211cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                        + Binder.getCallingUid() + " token: " + token);
22124df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                return;
22134df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            }
22144df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            long ident = Binder.clearCallingIdentity();
22154df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            try {
22164df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                showCurrentInputLocked(flags, null);
22179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
22189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Binder.restoreCallingIdentity(ident);
22199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void setEnabledSessionInMainThread(SessionState session) {
22249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnabledSession != session) {
22259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mEnabledSession != null) {
22269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
22278a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
22289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mEnabledSession.method.setSessionEnabled(
22299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mEnabledSession.session, false);
22309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
22319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
22329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEnabledSession = session;
22349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
22358a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
22369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                session.method.setSessionEnabled(
22379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        session.session, true);
22389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
22399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2242ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
224342c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
22449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean handleMessage(Message msg) {
2245758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov        SomeArgs args;
22469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (msg.what) {
22479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_SHOW_IM_PICKER:
22489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                showInputMethodMenu();
22499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
2250ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2251ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            case MSG_SHOW_IM_SUBTYPE_PICKER:
2252ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                showInputMethodSubtypeMenu();
2253ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                return true;
2254ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
225547a44916e2fb33cf4751906386d5f5c903b28d8bsatok            case MSG_SHOW_IM_SUBTYPE_ENABLER:
2256758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
22577fee71f66afef6421b92fa48e63d4bc73f5d0c27satok                showInputMethodAndSubtypeEnabler((String)args.arg1);
2258758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
2259217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                return true;
2260217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok
2261217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok            case MSG_SHOW_IM_CONFIG:
2262217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                showConfigureInputMethods();
226347a44916e2fb33cf4751906386d5f5c903b28d8bsatok                return true;
226447a44916e2fb33cf4751906386d5f5c903b28d8bsatok
22659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ---------------------------------------------------------
2266ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
22679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_UNBIND_INPUT:
22689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
22699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethod)msg.obj).unbindInput();
22709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
22719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // There is nothing interesting about the method dying.
22729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
22739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
22749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_BIND_INPUT:
2275758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
22769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
22779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethod)args.arg1).bindInput((InputBinding)args.arg2);
22789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
22799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2280758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
22819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
22829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_SHOW_SOFT_INPUT:
2283758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
22849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
22854df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    ((IInputMethod)args.arg1).showSoftInput(msg.arg1,
22864df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            (ResultReceiver)args.arg2);
22879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
22889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2289758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
22909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
22919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_HIDE_SOFT_INPUT:
2292758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
22939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
22944df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    ((IInputMethod)args.arg1).hideSoftInput(0,
22954df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            (ResultReceiver)args.arg2);
22969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
22979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2298758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
22999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
23009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_ATTACH_TOKEN:
2301758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
23029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23038a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.v(TAG, "Sending attach of token: " + args.arg2);
23049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethod)args.arg1).attachToken((IBinder)args.arg2);
23059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2307758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
23089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
23099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_CREATE_SESSION:
2310758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
23119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethod)args.arg1).createSession(
23139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (IInputMethodCallback)args.arg2);
23149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2316758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
23179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
23189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ---------------------------------------------------------
2319ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
23209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_START_INPUT:
2321758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
23229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SessionState session = (SessionState)args.arg1;
23249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setEnabledSessionInMainThread(session);
23259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    session.method.startInput((IInputContext)args.arg2,
23269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (EditorInfo)args.arg3);
23279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2329758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
23309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
23319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_RESTART_INPUT:
2332758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
23339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SessionState session = (SessionState)args.arg1;
23359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setEnabledSessionInMainThread(session);
23369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    session.method.restartInput((IInputContext)args.arg2,
23379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (EditorInfo)args.arg3);
23389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2340758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
23419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
2342ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
23439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ---------------------------------------------------------
2344ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
23459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_UNBIND_METHOD:
23469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1);
23489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // There is nothing interesting about the last client dying.
23509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
23519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
23529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_BIND_METHOD:
2353758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
23549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethodClient)args.arg1).onBindMethod(
23569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (InputBindResult)args.arg2);
23579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23588a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.w(TAG, "Client died receiving input method " + args.arg2);
23599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2360758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
23619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
2362a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn            case MSG_SET_ACTIVE:
2363a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                try {
2364a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                    ((ClientState)msg.obj).client.setActive(msg.arg1 != 0);
2365a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                } catch (RemoteException e) {
2366a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                    Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
2367a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                            + ((ClientState)msg.obj).pid + " uid "
2368a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                            + ((ClientState)msg.obj).uid);
2369a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                }
2370a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                return true;
237101038492ff0317f0d3cff54d8a7ee36bb31ff175satok
237201038492ff0317f0d3cff54d8a7ee36bb31ff175satok            // --------------------------------------------------------------
237301038492ff0317f0d3cff54d8a7ee36bb31ff175satok            case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
237401038492ff0317f0d3cff54d8a7ee36bb31ff175satok                mHardKeyboardListener.handleHardKeyboardStatusChange(
237501038492ff0317f0d3cff54d8a7ee36bb31ff175satok                        msg.arg1 == 1, msg.arg2 == 1);
237601038492ff0317f0d3cff54d8a7ee36bb31ff175satok                return true;
23779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
23799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23815b927c431f54ea47c3333afb7940d79e2e863f1asatok    private static boolean isSystemIme(InputMethodInfo inputMethod) {
23826da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        return (inputMethod.getServiceInfo().applicationInfo.flags
23836da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger                & ApplicationInfo.FLAG_SYSTEM) != 0;
23846da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger    }
23856da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
2386586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa    private static ArrayList<InputMethodSubtype> getSubtypes(InputMethodInfo imi) {
2387586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
2388586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        final int subtypeCount = imi.getSubtypeCount();
2389586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        for (int i = 0; i < subtypeCount; ++i) {
2390586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa            subtypes.add(imi.getSubtypeAt(i));
2391586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        }
2392586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        return subtypes;
2393586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa    }
2394586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa
2395a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok    private static ArrayList<InputMethodSubtype> getOverridingImplicitlyEnabledSubtypes(
2396a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            InputMethodInfo imi, String mode) {
2397a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
2398a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        final int subtypeCount = imi.getSubtypeCount();
2399a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        for (int i = 0; i < subtypeCount; ++i) {
2400a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            final InputMethodSubtype subtype = imi.getSubtypeAt(i);
2401a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            if (subtype.overridesImplicitlyEnabledSubtype() && subtype.getMode().equals(mode)) {
2402a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                subtypes.add(subtype);
2403a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            }
2404a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        }
2405a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        return subtypes;
2406a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok    }
2407a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok
2408dc9ddaee9a710cf6f5d7f37350650f82e706c706satok    private InputMethodInfo getMostApplicableDefaultIMELocked() {
2409d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
24106da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        if (enabled != null && enabled.size() > 0) {
241183e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn            // We'd prefer to fall back on a system IME, since that is safer.
24120a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            int i = enabled.size();
24130a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            int firstFoundSystemIme = -1;
241483e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn            while (i > 0) {
241583e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn                i--;
2416dc9ddaee9a710cf6f5d7f37350650f82e706c706satok                final InputMethodInfo imi = enabled.get(i);
24170a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                if (isSystemImeThatHasEnglishSubtype(imi) && !imi.isAuxiliaryIme()) {
24180a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                    return imi;
24190a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                }
24200a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                if (firstFoundSystemIme < 0 && isSystemIme(imi) && !imi.isAuxiliaryIme()) {
24210a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                    firstFoundSystemIme = i;
242283e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn                }
242383e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn            }
24240a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            return enabled.get(Math.max(firstFoundSystemIme, 0));
2425dc9ddaee9a710cf6f5d7f37350650f82e706c706satok        }
2426dc9ddaee9a710cf6f5d7f37350650f82e706c706satok        return null;
2427dc9ddaee9a710cf6f5d7f37350650f82e706c706satok    }
2428dc9ddaee9a710cf6f5d7f37350650f82e706c706satok
2429dc9ddaee9a710cf6f5d7f37350650f82e706c706satok    private boolean chooseNewDefaultIMELocked() {
2430dc9ddaee9a710cf6f5d7f37350650f82e706c706satok        final InputMethodInfo imi = getMostApplicableDefaultIMELocked();
2431dc9ddaee9a710cf6f5d7f37350650f82e706c706satok        if (imi != null) {
243203eb319a3a7fe6fe9ab9eba6fc1f727285850906satok            if (DEBUG) {
243303eb319a3a7fe6fe9ab9eba6fc1f727285850906satok                Slog.d(TAG, "New default IME was selected: " + imi.getId());
243403eb319a3a7fe6fe9ab9eba6fc1f727285850906satok            }
2435723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            resetSelectedInputMethodAndSubtypeLocked(imi.getId());
24366da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger            return true;
24376da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        }
24386da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
24396da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        return false;
24406da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger    }
24416da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
24429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void buildInputMethodListLocked(ArrayList<InputMethodInfo> list,
24439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            HashMap<String, InputMethodInfo> map) {
24444e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (DEBUG) {
24454e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Slog.d(TAG, "--- re-buildInputMethodList " + ", \n ------ \n" + getStackTrace());
24464e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
24479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        list.clear();
24489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.clear();
2449ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
24504e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // Use for queryIntentServicesAsUser
24514e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final PackageManager pm = mContext.getPackageManager();
24527d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn        final Configuration config = mRes.getConfiguration();
2453e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani        final boolean haveHardKeyboard = config.keyboard == Configuration.KEYBOARD_QWERTY;
24544e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        String disabledSysImes = mSettings.getDisabledSystemInputMethods();
2455e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani        if (disabledSysImes == null) disabledSysImes = "";
24569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24574e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
24589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                new Intent(InputMethod.SERVICE_INTERFACE),
24594e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                PackageManager.GET_META_DATA, mSettings.getCurrentUserId());
2460ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2461e7c6998e0a953ae55487d4fe122739646f9280aasatok        final HashMap<String, List<InputMethodSubtype>> additionalSubtypes =
2462e7c6998e0a953ae55487d4fe122739646f9280aasatok                mFileManager.getAllAdditionalInputMethodSubtypes();
24639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < services.size(); ++i) {
24649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ResolveInfo ri = services.get(i);
24659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ServiceInfo si = ri.serviceInfo;
24669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ComponentName compName = new ComponentName(si.packageName, si.name);
24679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!android.Manifest.permission.BIND_INPUT_METHOD.equals(
24689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    si.permission)) {
24698a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Skipping input method " + compName
24709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + ": it does not require the permission "
24719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + android.Manifest.permission.BIND_INPUT_METHOD);
24729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
24739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
24749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24758a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.d(TAG, "Checking " + compName);
24769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
2478e7c6998e0a953ae55487d4fe122739646f9280aasatok                InputMethodInfo p = new InputMethodInfo(mContext, ri, additionalSubtypes);
24799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                list.add(p);
2480e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani                final String id = p.getId();
2481e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani                map.put(id, p);
24829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24835b927c431f54ea47c3333afb7940d79e2e863f1asatok                // Valid system default IMEs and IMEs that have English subtypes are enabled
24845b927c431f54ea47c3333afb7940d79e2e863f1asatok                // by default, unless there's a hard keyboard and the system IME was explicitly
24855b927c431f54ea47c3333afb7940d79e2e863f1asatok                // disabled
24865b927c431f54ea47c3333afb7940d79e2e863f1asatok                if ((isValidSystemDefaultIme(p, mContext) || isSystemImeThatHasEnglishSubtype(p))
24875b927c431f54ea47c3333afb7940d79e2e863f1asatok                        && (!haveHardKeyboard || disabledSysImes.indexOf(id) < 0)) {
2488e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani                    setInputMethodEnabledLocked(id, true);
24896da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger                }
24906da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
24919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (DEBUG) {
24928a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.d(TAG, "Found a third-party input method " + p);
24939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2494ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
24959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (XmlPullParserException e) {
24968a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Unable to load input method " + compName, e);
24979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IOException e) {
24988a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Unable to load input method " + compName, e);
24999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25016da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
25024e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final String defaultImiId = mSettings.getSelectedInputMethod();
25030a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok        if (!TextUtils.isEmpty(defaultImiId)) {
25040a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            if (!map.containsKey(defaultImiId)) {
25050a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                Slog.w(TAG, "Default IME is uninstalled. Choose new default IME.");
25060a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                if (chooseNewDefaultIMELocked()) {
25070a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                    updateFromSettingsLocked();
25080a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                }
25090a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            } else {
25100a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                // Double check that the default IME is certainly enabled.
25110a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                setInputMethodEnabledLocked(defaultImiId, true);
25126da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger            }
25136da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        }
25149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2515ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
25169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ----------------------------------------------------------------------
2517ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2518ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private void showInputMethodMenu() {
2519ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        showInputMethodMenuInternal(false);
2520ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
2521ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2522ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private void showInputMethodSubtypeMenu() {
2523ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        showInputMethodMenuInternal(true);
2524ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
2525ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2526217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok    private void showInputMethodAndSubtypeEnabler(String inputMethodId) {
2527f49688fa17b70313c0734f00df73bc3308a749e9Tadashi G. Takaoka        Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
252847a44916e2fb33cf4751906386d5f5c903b28d8bsatok        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
252986417ea3f8041481a085823a1aa9f66d747231e8satok                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
253086417ea3f8041481a085823a1aa9f66d747231e8satok                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
25317fee71f66afef6421b92fa48e63d4bc73f5d0c27satok        if (!TextUtils.isEmpty(inputMethodId)) {
25322548020c364c4119d134c84cc7a00ffca2dcbe7bTadashi G. Takaoka            intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
25337fee71f66afef6421b92fa48e63d4bc73f5d0c27satok        }
25343ba439d6481b7f23ade44bfde0700aaa1e076a32Satoshi Kataoka        mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
2535217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok    }
2536217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok
2537217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok    private void showConfigureInputMethods() {
2538217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok        Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
2539217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
2540217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
2541217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
25423ba439d6481b7f23ade44bfde0700aaa1e076a32Satoshi Kataoka        mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
254347a44916e2fb33cf4751906386d5f5c903b28d8bsatok    }
254447a44916e2fb33cf4751906386d5f5c903b28d8bsatok
25452c93efc9eb188532472edc9e0c3e1ab8121aa20dsatok    private boolean isScreenLocked() {
25462c93efc9eb188532472edc9e0c3e1ab8121aa20dsatok        return mKeyguardManager != null
25472c93efc9eb188532472edc9e0c3e1ab8121aa20dsatok                && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure();
25482c93efc9eb188532472edc9e0c3e1ab8121aa20dsatok    }
2549ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private void showInputMethodMenuInternal(boolean showSubtypes) {
25508a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        if (DEBUG) Slog.v(TAG, "Show switching menu");
25519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Context context = mContext;
25532c93efc9eb188532472edc9e0c3e1ab8121aa20dsatok        final boolean isScreenLocked = isScreenLocked();
2554ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
25554e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final String lastInputMethodId = mSettings.getSelectedInputMethod();
2556ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        int lastInputMethodSubtypeId = getSelectedInputMethodSubtypeId(lastInputMethodId);
25578a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
2558ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
25597f35c8cc88bea5230f001dd4356f864845d202e5satok        synchronized (mMethodMap) {
2560bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            final HashMap<InputMethodInfo, List<InputMethodSubtype>> immis =
2561bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                    getExplicitlyOrImplicitlyEnabledInputMethodsAndSubtypeListLocked();
25627f35c8cc88bea5230f001dd4356f864845d202e5satok            if (immis == null || immis.size() == 0) {
25637f35c8cc88bea5230f001dd4356f864845d202e5satok                return;
25647f35c8cc88bea5230f001dd4356f864845d202e5satok            }
2565ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
25668cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            hideInputMethodMenuLocked();
25679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2568688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            final List<ImeSubtypeListItem> imList =
2569688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    mImListManager.getSortedInputMethodAndSubtypeList(
2570688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            showSubtypes, mInputShown, isScreenLocked);
2571913a8925c07e854a80bf5df87561f290d3a56d61satok
2572c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok            if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
25734e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtypeLocked();
2574c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                if (currentSubtype != null) {
2575c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                    final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
2576c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                    lastInputMethodSubtypeId =
2577c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                            getSubtypeIdFromHashCode(currentImi, currentSubtype.hashCode());
2578c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                }
2579c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok            }
2580c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok
2581761eb3762f3602dd1859905ee4ba80f0ef6aec56Ken Wakasa            final int N = imList.size();
2582ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            mIms = new InputMethodInfo[N];
2583ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            mSubtypeIds = new int[N];
25848cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            int checkedItem = 0;
25858cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            for (int i = 0; i < N; ++i) {
258605dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                final ImeSubtypeListItem item = imList.get(i);
258705dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                mIms[i] = item.mImi;
258805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                mSubtypeIds[i] = item.mSubtypeId;
25898cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                if (mIms[i].getId().equals(lastInputMethodId)) {
2590ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    int subtypeId = mSubtypeIds[i];
2591ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    if ((subtypeId == NOT_A_SUBTYPE_ID)
2592ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                            || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0)
2593ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                            || (subtypeId == lastInputMethodSubtypeId)) {
2594ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                        checkedItem = i;
2595ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    }
25968cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                }
25979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
259805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final TypedArray a = context.obtainStyledAttributes(null,
25998cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    com.android.internal.R.styleable.DialogPreference,
26008cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    com.android.internal.R.attr.alertDialogStyle, 0);
26018cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            mDialogBuilder = new AlertDialog.Builder(context)
26028cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    .setOnCancelListener(new OnCancelListener() {
260342c5a1666c4e576ccd5974233513100aad2c1534satok                        @Override
26048cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                        public void onCancel(DialogInterface dialog) {
26059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            hideInputMethodMenu();
26068cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                        }
26078cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    })
26088cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    .setIcon(a.getDrawable(
26098cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                            com.android.internal.R.styleable.DialogPreference_dialogTitle));
26108cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            a.recycle();
261101038492ff0317f0d3cff54d8a7ee36bb31ff175satok            final LayoutInflater inflater =
261201038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
261301038492ff0317f0d3cff54d8a7ee36bb31ff175satok            final View tv = inflater.inflate(
261401038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    com.android.internal.R.layout.input_method_switch_dialog_title, null);
261501038492ff0317f0d3cff54d8a7ee36bb31ff175satok            mDialogBuilder.setCustomTitle(tv);
261601038492ff0317f0d3cff54d8a7ee36bb31ff175satok
261701038492ff0317f0d3cff54d8a7ee36bb31ff175satok            // Setup layout for a toggle switch of the hardware keyboard
261801038492ff0317f0d3cff54d8a7ee36bb31ff175satok            mSwitchingDialogTitleView = tv;
261901038492ff0317f0d3cff54d8a7ee36bb31ff175satok            mSwitchingDialogTitleView.findViewById(
262001038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    com.android.internal.R.id.hard_keyboard_section).setVisibility(
262101038492ff0317f0d3cff54d8a7ee36bb31ff175satok                            mWindowManagerService.isHardKeyboardAvailable() ?
262201038492ff0317f0d3cff54d8a7ee36bb31ff175satok                                    View.VISIBLE : View.GONE);
262301038492ff0317f0d3cff54d8a7ee36bb31ff175satok            final Switch hardKeySwitch =  ((Switch)mSwitchingDialogTitleView.findViewById(
262401038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    com.android.internal.R.id.hard_keyboard_switch));
262501038492ff0317f0d3cff54d8a7ee36bb31ff175satok            hardKeySwitch.setChecked(mWindowManagerService.isHardKeyboardEnabled());
262601038492ff0317f0d3cff54d8a7ee36bb31ff175satok            hardKeySwitch.setOnCheckedChangeListener(
262701038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    new OnCheckedChangeListener() {
262801038492ff0317f0d3cff54d8a7ee36bb31ff175satok                        @Override
262901038492ff0317f0d3cff54d8a7ee36bb31ff175satok                        public void onCheckedChanged(
263001038492ff0317f0d3cff54d8a7ee36bb31ff175satok                                CompoundButton buttonView, boolean isChecked) {
263101038492ff0317f0d3cff54d8a7ee36bb31ff175satok                            mWindowManagerService.setHardKeyboardEnabled(isChecked);
263201038492ff0317f0d3cff54d8a7ee36bb31ff175satok                        }
263301038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    });
2634d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
263505dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(context,
263605dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                    com.android.internal.R.layout.simple_list_item_2_single_choice, imList,
263705dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                    checkedItem);
263805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa
263905dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mDialogBuilder.setSingleChoiceItems(adapter, checkedItem,
26408cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    new AlertDialog.OnClickListener() {
264142c5a1666c4e576ccd5974233513100aad2c1534satok                        @Override
26428cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                        public void onClick(DialogInterface dialog, int which) {
26438cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                            synchronized (mMethodMap) {
2644ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                if (mIms == null || mIms.length <= which
2645ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                        || mSubtypeIds == null || mSubtypeIds.length <= which) {
26468cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                    return;
26478cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                }
26488cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                InputMethodInfo im = mIms[which];
2649ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                int subtypeId = mSubtypeIds[which];
26508cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                hideInputMethodMenu();
26518cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                if (im != null) {
2652ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                    if ((subtypeId < 0)
2653586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                                            || (subtypeId >= im.getSubtypeCount())) {
2654ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                        subtypeId = NOT_A_SUBTYPE_ID;
2655ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                    }
2656ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                    setInputMethodLocked(im.getId(), subtypeId);
26578cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                }
265820cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn                            }
26599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
26608cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    });
26619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2662bc81b692d51a9cd6f9d61584aacd8308ac3366easatok            if (showSubtypes && !isScreenLocked) {
266382beadfa067b1e286fa604f8d7960d769411c954satok                mDialogBuilder.setPositiveButton(
266482beadfa067b1e286fa604f8d7960d769411c954satok                        com.android.internal.R.string.configure_input_methods,
26657f35c8cc88bea5230f001dd4356f864845d202e5satok                        new DialogInterface.OnClickListener() {
266642c5a1666c4e576ccd5974233513100aad2c1534satok                            @Override
26677f35c8cc88bea5230f001dd4356f864845d202e5satok                            public void onClick(DialogInterface dialog, int whichButton) {
2668217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                                showConfigureInputMethods();
26697f35c8cc88bea5230f001dd4356f864845d202e5satok                            }
26707f35c8cc88bea5230f001dd4356f864845d202e5satok                        });
26717f35c8cc88bea5230f001dd4356f864845d202e5satok            }
26729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSwitchingDialog = mDialogBuilder.create();
2673e3a7f628c6d9fef42be24999b3137ebe5c6f3525Dianne Hackborn            mSwitchingDialog.setCanceledOnTouchOutside(true);
26749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSwitchingDialog.getWindow().setType(
26759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
2676c86884cd839123e3be3cc97c8f293ac47d3624a9Satoshi Kataoka            mSwitchingDialog.getWindow().getAttributes().privateFlags |=
2677c86884cd839123e3be3cc97c8f293ac47d3624a9Satoshi Kataoka                    WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
2678e3a7f628c6d9fef42be24999b3137ebe5c6f3525Dianne Hackborn            mSwitchingDialog.getWindow().getAttributes().setTitle("Select input method");
26799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSwitchingDialog.show();
26809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2682ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
268393d744deb167d5c681b5bb5627fd36a92f1ea79asatok    private static class ImeSubtypeListItem implements Comparable<ImeSubtypeListItem> {
268405dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        public final CharSequence mImeName;
268505dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        public final CharSequence mSubtypeName;
268605dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        public final InputMethodInfo mImi;
268705dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        public final int mSubtypeId;
268893d744deb167d5c681b5bb5627fd36a92f1ea79asatok        private final boolean mIsSystemLocale;
268993d744deb167d5c681b5bb5627fd36a92f1ea79asatok        private final boolean mIsSystemLanguage;
269093d744deb167d5c681b5bb5627fd36a92f1ea79asatok
269105dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        public ImeSubtypeListItem(CharSequence imeName, CharSequence subtypeName,
269293d744deb167d5c681b5bb5627fd36a92f1ea79asatok                InputMethodInfo imi, int subtypeId, String subtypeLocale, String systemLocale) {
269305dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mImeName = imeName;
269405dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mSubtypeName = subtypeName;
269505dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mImi = imi;
269605dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mSubtypeId = subtypeId;
269793d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (TextUtils.isEmpty(subtypeLocale)) {
269893d744deb167d5c681b5bb5627fd36a92f1ea79asatok                mIsSystemLocale = false;
269993d744deb167d5c681b5bb5627fd36a92f1ea79asatok                mIsSystemLanguage = false;
270093d744deb167d5c681b5bb5627fd36a92f1ea79asatok            } else {
270193d744deb167d5c681b5bb5627fd36a92f1ea79asatok                mIsSystemLocale = subtypeLocale.equals(systemLocale);
270293d744deb167d5c681b5bb5627fd36a92f1ea79asatok                mIsSystemLanguage = mIsSystemLocale
270393d744deb167d5c681b5bb5627fd36a92f1ea79asatok                        || subtypeLocale.startsWith(systemLocale.substring(0, 2));
270493d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
270593d744deb167d5c681b5bb5627fd36a92f1ea79asatok        }
270693d744deb167d5c681b5bb5627fd36a92f1ea79asatok
270793d744deb167d5c681b5bb5627fd36a92f1ea79asatok        @Override
270893d744deb167d5c681b5bb5627fd36a92f1ea79asatok        public int compareTo(ImeSubtypeListItem other) {
270993d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (TextUtils.isEmpty(mImeName)) {
271093d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return 1;
271193d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
271293d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (TextUtils.isEmpty(other.mImeName)) {
271393d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return -1;
271493d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
271593d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (!TextUtils.equals(mImeName, other.mImeName)) {
271693d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return mImeName.toString().compareTo(other.mImeName.toString());
271793d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
271893d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (TextUtils.equals(mSubtypeName, other.mSubtypeName)) {
271993d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return 0;
272093d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
272193d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (mIsSystemLocale) {
272293d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return -1;
272393d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
272493d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (other.mIsSystemLocale) {
272593d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return 1;
272693d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
272793d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (mIsSystemLanguage) {
272893d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return -1;
272993d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
273093d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (other.mIsSystemLanguage) {
273193d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return 1;
273293d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
273393d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (TextUtils.isEmpty(mSubtypeName)) {
273493d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return 1;
273593d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
273693d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (TextUtils.isEmpty(other.mSubtypeName)) {
273793d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return -1;
273893d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
273993d744deb167d5c681b5bb5627fd36a92f1ea79asatok            return mSubtypeName.toString().compareTo(other.mSubtypeName.toString());
274005dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        }
274105dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa    }
274205dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa
274305dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa    private static class ImeSubtypeListAdapter extends ArrayAdapter<ImeSubtypeListItem> {
274405dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        private final LayoutInflater mInflater;
274505dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        private final int mTextViewResourceId;
274605dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        private final List<ImeSubtypeListItem> mItemsList;
274705dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        private final int mCheckedItem;
274805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        public ImeSubtypeListAdapter(Context context, int textViewResourceId,
274905dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                List<ImeSubtypeListItem> itemsList, int checkedItem) {
275005dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            super(context, textViewResourceId, itemsList);
275105dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mTextViewResourceId = textViewResourceId;
275205dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mItemsList = itemsList;
275305dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mCheckedItem = checkedItem;
275405dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
275505dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        }
275605dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa
275705dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        @Override
275805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        public View getView(int position, View convertView, ViewGroup parent) {
275905dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final View view = convertView != null ? convertView
276005dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                    : mInflater.inflate(mTextViewResourceId, null);
276105dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            if (position < 0 || position >= mItemsList.size()) return view;
276205dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final ImeSubtypeListItem item = mItemsList.get(position);
276305dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final CharSequence imeName = item.mImeName;
276405dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final CharSequence subtypeName = item.mSubtypeName;
276505dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final TextView firstTextView = (TextView)view.findViewById(android.R.id.text1);
276605dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final TextView secondTextView = (TextView)view.findViewById(android.R.id.text2);
276705dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            if (TextUtils.isEmpty(subtypeName)) {
276805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                firstTextView.setText(imeName);
276905dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                secondTextView.setVisibility(View.GONE);
277005dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            } else {
277105dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                firstTextView.setText(subtypeName);
277205dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                secondTextView.setText(imeName);
277305dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                secondTextView.setVisibility(View.VISIBLE);
277405dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            }
277505dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final RadioButton radioButton =
277605dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                    (RadioButton)view.findViewById(com.android.internal.R.id.radio);
277705dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            radioButton.setChecked(position == mCheckedItem);
277805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            return view;
277905dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        }
278005dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa    }
278105dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa
27829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void hideInputMethodMenu() {
2783105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        synchronized (mMethodMap) {
2784105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            hideInputMethodMenuLocked();
2785105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
2786105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
2787ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2788105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    void hideInputMethodMenuLocked() {
27898a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        if (DEBUG) Slog.v(TAG, "Hide switching menu");
27909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2791105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (mSwitchingDialog != null) {
2792105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mSwitchingDialog.dismiss();
2793105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mSwitchingDialog = null;
27949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2795ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2796105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mDialogBuilder = null;
2797105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mIms = null;
27989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2799ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
28009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ----------------------------------------------------------------------
2801ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
280242c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
28039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean setInputMethodEnabled(String id, boolean enabled) {
28044e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // TODO: Make this work even for non-current users?
28054e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
28064e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
28074e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
28089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
28099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mContext.checkCallingOrSelfPermission(
28109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    android.Manifest.permission.WRITE_SECURE_SETTINGS)
28119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    != PackageManager.PERMISSION_GRANTED) {
28129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new SecurityException(
28139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "Requires permission "
28149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + android.Manifest.permission.WRITE_SECURE_SETTINGS);
28159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
281621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
28179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long ident = Binder.clearCallingIdentity();
28189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
281921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                return setInputMethodEnabledLocked(id, enabled);
282021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            } finally {
282121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                Binder.restoreCallingIdentity(ident);
282221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            }
282321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        }
282421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    }
282521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
282621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    boolean setInputMethodEnabledLocked(String id, boolean enabled) {
282721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        // Make sure this is a valid input method.
282821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        InputMethodInfo imm = mMethodMap.get(id);
282921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        if (imm == null) {
2830d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
283121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        }
2832ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2833d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
2834d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                .getEnabledInputMethodsAndSubtypeListLocked();
2835ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2836d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        if (enabled) {
2837d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
2838d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                if (pair.first.equals(id)) {
2839d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // We are enabling this input method, but it is already enabled.
2840d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // Nothing to do. The previous state was enabled.
2841d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    return true;
28429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
284321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            }
2844d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mSettings.appendAndPutEnabledInputMethodLocked(id, false);
2845d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            // Previous state was disabled.
2846d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return false;
2847d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        } else {
2848d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            StringBuilder builder = new StringBuilder();
2849d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (mSettings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
2850d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    builder, enabledInputMethodsList, id)) {
2851d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Disabled input method is currently selected, switch to another one.
28524e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                final String selId = mSettings.getSelectedInputMethod();
285303eb319a3a7fe6fe9ab9eba6fc1f727285850906satok                if (id.equals(selId) && !chooseNewDefaultIMELocked()) {
285403eb319a3a7fe6fe9ab9eba6fc1f727285850906satok                    Slog.i(TAG, "Can't find new IME, unsetting the current input method.");
285503eb319a3a7fe6fe9ab9eba6fc1f727285850906satok                    resetSelectedInputMethodAndSubtypeLocked("");
2856d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
2857d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Previous state was enabled.
2858d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                return true;
2859d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            } else {
2860d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // We are disabling the input method but it is already disabled.
2861d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Nothing to do.  The previous state was disabled.
28629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
28639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28664df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project
286757ffc00239edcfe733832771e1429fca20182207satok    private boolean canAddToLastInputMethod(InputMethodSubtype subtype) {
286857ffc00239edcfe733832771e1429fca20182207satok        if (subtype == null) return true;
28699b4157935af9e44571187a9533c2cc9b413383bfsatok        return !subtype.isAuxiliary();
287057ffc00239edcfe733832771e1429fca20182207satok    }
287157ffc00239edcfe733832771e1429fca20182207satok
2872723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    private void saveCurrentInputMethodAndSubtypeToHistory() {
2873723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        String subtypeId = NOT_A_SUBTYPE_ID_STR;
2874723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        if (mCurrentSubtype != null) {
2875723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            subtypeId = String.valueOf(mCurrentSubtype.hashCode());
2876723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
287757ffc00239edcfe733832771e1429fca20182207satok        if (canAddToLastInputMethod(mCurrentSubtype)) {
287857ffc00239edcfe733832771e1429fca20182207satok            mSettings.addSubtypeToHistory(mCurMethodId, subtypeId);
287957ffc00239edcfe733832771e1429fca20182207satok        }
2880ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
2881ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2882723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
2883723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            boolean setSubtypeOnly) {
2884723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        // Update the history of InputMethod and Subtype
2885723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        saveCurrentInputMethodAndSubtypeToHistory();
2886723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2887723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        // Set Subtype here
2888723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        if (imi == null || subtypeId < 0) {
2889723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
28900ba75bb22c2992f649ee5f7605a2b45442ad4862Tadashi G. Takaoka            mCurrentSubtype = null;
2891723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        } else {
2892586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa            if (subtypeId < imi.getSubtypeCount()) {
2893586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                InputMethodSubtype subtype = imi.getSubtypeAt(subtypeId);
2894586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                mSettings.putSelectedSubtype(subtype.hashCode());
2895586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                mCurrentSubtype = subtype;
2896723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            } else {
2897723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
2898d81e950265356c81276b73da68a535ffa48d72f0satok                // If the subtype is not specified, choose the most applicable one
28994e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                mCurrentSubtype = getCurrentInputMethodSubtypeLocked();
2900723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2901723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2902723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
29034c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // Workaround.
29044c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // ASEC is not ready in the IMMS constructor. Accordingly, forward-locked
29054c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // IMEs are not recognized and considered uninstalled.
29064c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // Actually, we can't move everything after SystemReady because
29074c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // IMMS needs to run in the encryption lock screen. So, we just skip changing
29084c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // the default IME here and try cheking the default IME again in systemReady().
29094c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // TODO: Do nothing before system ready and implement a separated logic for
29104c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // the encryption lock screen.
29114c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // TODO: ASEC should be ready before IMMS is instantiated.
29124c0e7152e74d091eb78af8baacd38287ba95a1a1satok        if (mSystemReady && !setSubtypeOnly) {
2913723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // Set InputMethod here
2914723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mSettings.putSelectedInputMethod(imi != null ? imi.getId() : "");
29151ab852fbcfe155c9d4373b7130f8515591669634satok        }
2916ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
2917ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2918723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
2919723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        InputMethodInfo imi = mMethodMap.get(newDefaultIme);
2920723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        int lastSubtypeId = NOT_A_SUBTYPE_ID;
2921723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        // newDefaultIme is empty when there is no candidate for the selected IME.
2922723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        if (imi != null && !TextUtils.isEmpty(newDefaultIme)) {
2923723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            String subtypeHashCode = mSettings.getLastSubtypeForInputMethodLocked(newDefaultIme);
2924723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (subtypeHashCode != null) {
2925723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                try {
2926723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    lastSubtypeId = getSubtypeIdFromHashCode(
2927723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                            imi, Integer.valueOf(subtypeHashCode));
2928723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                } catch (NumberFormatException e) {
2929723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    Slog.w(TAG, "HashCode for subtype looks broken: " + subtypeHashCode, e);
2930723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
2931723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2932723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2933723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        setSelectedInputMethodAndSubtypeLocked(imi, lastSubtypeId, false);
2934723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    }
2935723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2936ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private int getSelectedInputMethodSubtypeId(String id) {
2937ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        InputMethodInfo imi = mMethodMap.get(id);
2938ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        if (imi == null) {
2939ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            return NOT_A_SUBTYPE_ID;
2940ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        }
29414e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final int subtypeHashCode = mSettings.getSelectedInputMethodSubtypeHashCode();
29424e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        return getSubtypeIdFromHashCode(imi, subtypeHashCode);
2943723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    }
2944723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2945fdf419e81d795593e3792c9e78f33ed899ff098esatok    private static boolean isValidSubtypeId(InputMethodInfo imi, int subtypeHashCode) {
2946fdf419e81d795593e3792c9e78f33ed899ff098esatok        return getSubtypeIdFromHashCode(imi, subtypeHashCode) != NOT_A_SUBTYPE_ID;
2947fdf419e81d795593e3792c9e78f33ed899ff098esatok    }
2948fdf419e81d795593e3792c9e78f33ed899ff098esatok
2949fdf419e81d795593e3792c9e78f33ed899ff098esatok    private static int getSubtypeIdFromHashCode(InputMethodInfo imi, int subtypeHashCode) {
29502820351489537698ad153c6397edf3270455edc5satok        if (imi != null) {
2951586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa            final int subtypeCount = imi.getSubtypeCount();
2952586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa            for (int i = 0; i < subtypeCount; ++i) {
2953586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                InputMethodSubtype ims = imi.getSubtypeAt(i);
29542820351489537698ad153c6397edf3270455edc5satok                if (subtypeHashCode == ims.hashCode()) {
29552820351489537698ad153c6397edf3270455edc5satok                    return i;
29562820351489537698ad153c6397edf3270455edc5satok                }
2957ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            }
2958ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        }
2959ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        return NOT_A_SUBTYPE_ID;
2960ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
2961ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2962a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok    private static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
2963a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            Resources res, InputMethodInfo imi) {
2964a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        final List<InputMethodSubtype> subtypes = getSubtypes(imi);
2965df31ae6a3011d47421a6ac10021f9649dc34a156satok        final String systemLocale = res.getConfiguration().locale.toString();
29663da922367c0dbe67b97fe97fcfca13fd93602f7asatok        if (TextUtils.isEmpty(systemLocale)) return new ArrayList<InputMethodSubtype>();
29674a553e3a70d26fac5d7b7ec1142e0cabfdd66670satok        final HashMap<String, InputMethodSubtype> applicableModeAndSubtypesMap =
29683da922367c0dbe67b97fe97fcfca13fd93602f7asatok                new HashMap<String, InputMethodSubtype>();
296916331c8a1d33defccc5cbb18694def79196c921bsatok        final int N = subtypes.size();
297016331c8a1d33defccc5cbb18694def79196c921bsatok        for (int i = 0; i < N; ++i) {
2971a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            // scan overriding implicitly enabled subtypes.
2972a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            InputMethodSubtype subtype = subtypes.get(i);
2973a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            if (subtype.overridesImplicitlyEnabledSubtype()) {
2974a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                final String mode = subtype.getMode();
2975a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                if (!applicableModeAndSubtypesMap.containsKey(mode)) {
2976a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                    applicableModeAndSubtypesMap.put(mode, subtype);
2977a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                }
2978a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            }
2979a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        }
2980a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        if (applicableModeAndSubtypesMap.size() > 0) {
2981a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            return new ArrayList<InputMethodSubtype>(applicableModeAndSubtypesMap.values());
2982a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        }
2983a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        for (int i = 0; i < N; ++i) {
29844a553e3a70d26fac5d7b7ec1142e0cabfdd66670satok            final InputMethodSubtype subtype = subtypes.get(i);
29853da922367c0dbe67b97fe97fcfca13fd93602f7asatok            final String locale = subtype.getLocale();
29863da922367c0dbe67b97fe97fcfca13fd93602f7asatok            final String mode = subtype.getMode();
29873da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // When system locale starts with subtype's locale, that subtype will be applicable
29883da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // for system locale
29893da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // For instance, it's clearly applicable for cases like system locale = en_US and
29903da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // subtype = en, but it is not necessarily considered applicable for cases like system
29913da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // locale = en and subtype = en_US.
29923da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // We just call systemLocale.startsWith(locale) in this function because there is no
29933da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // need to find applicable subtypes aggressively unlike
29943da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // findLastResortApplicableSubtypeLocked.
29953da922367c0dbe67b97fe97fcfca13fd93602f7asatok            if (systemLocale.startsWith(locale)) {
29964a553e3a70d26fac5d7b7ec1142e0cabfdd66670satok                final InputMethodSubtype applicableSubtype = applicableModeAndSubtypesMap.get(mode);
29973da922367c0dbe67b97fe97fcfca13fd93602f7asatok                // If more applicable subtypes are contained, skip.
29984a553e3a70d26fac5d7b7ec1142e0cabfdd66670satok                if (applicableSubtype != null) {
29994a553e3a70d26fac5d7b7ec1142e0cabfdd66670satok                    if (systemLocale.equals(applicableSubtype.getLocale())) continue;
30004a553e3a70d26fac5d7b7ec1142e0cabfdd66670satok                    if (!systemLocale.equals(locale)) continue;
30014a553e3a70d26fac5d7b7ec1142e0cabfdd66670satok                }
30023da922367c0dbe67b97fe97fcfca13fd93602f7asatok                applicableModeAndSubtypesMap.put(mode, subtype);
300316331c8a1d33defccc5cbb18694def79196c921bsatok            }
300416331c8a1d33defccc5cbb18694def79196c921bsatok        }
3005c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok        final InputMethodSubtype keyboardSubtype
3006c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                = applicableModeAndSubtypesMap.get(SUBTYPE_MODE_KEYBOARD);
30074a28bde70e23b2ed151d52690da702da7f23cf5esatok        final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<InputMethodSubtype>(
30083da922367c0dbe67b97fe97fcfca13fd93602f7asatok                applicableModeAndSubtypesMap.values());
3009c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok        if (keyboardSubtype != null && !keyboardSubtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) {
3010c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok            for (int i = 0; i < N; ++i) {
3011c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                final InputMethodSubtype subtype = subtypes.get(i);
3012c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                final String mode = subtype.getMode();
3013c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                if (SUBTYPE_MODE_KEYBOARD.equals(mode) && subtype.containsExtraValueKey(
3014c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                        TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)) {
3015c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                    applicableSubtypes.add(subtype);
3016c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                }
3017c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok            }
3018c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok        }
3019c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok        if (keyboardSubtype == null) {
302016331c8a1d33defccc5cbb18694def79196c921bsatok            InputMethodSubtype lastResortKeyboardSubtype = findLastResortApplicableSubtypeLocked(
3021df31ae6a3011d47421a6ac10021f9649dc34a156satok                    res, subtypes, SUBTYPE_MODE_KEYBOARD, systemLocale, true);
302216331c8a1d33defccc5cbb18694def79196c921bsatok            if (lastResortKeyboardSubtype != null) {
302316331c8a1d33defccc5cbb18694def79196c921bsatok                applicableSubtypes.add(lastResortKeyboardSubtype);
302416331c8a1d33defccc5cbb18694def79196c921bsatok            }
302516331c8a1d33defccc5cbb18694def79196c921bsatok        }
302616331c8a1d33defccc5cbb18694def79196c921bsatok        return applicableSubtypes;
302716331c8a1d33defccc5cbb18694def79196c921bsatok    }
302816331c8a1d33defccc5cbb18694def79196c921bsatok
30294e4569dab5c75804b01a19b2d6e6101b445c1c68satok    /**
30304e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * If there are no selected subtypes, tries finding the most applicable one according to the
30314e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * given locale.
30324e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * @param subtypes this function will search the most applicable subtype in subtypes
30334e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * @param mode subtypes will be filtered by mode
30344e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * @param locale subtypes will be filtered by locale
30357599a7fb1ab5b75ca801f7d7e448f4c097320e01satok     * @param canIgnoreLocaleAsLastResort if this function can't find the most applicable subtype,
30367599a7fb1ab5b75ca801f7d7e448f4c097320e01satok     * it will return the first subtype matched with mode
30374e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * @return the most applicable subtypeId
30384e4569dab5c75804b01a19b2d6e6101b445c1c68satok     */
3039df31ae6a3011d47421a6ac10021f9649dc34a156satok    private static InputMethodSubtype findLastResortApplicableSubtypeLocked(
3040df31ae6a3011d47421a6ac10021f9649dc34a156satok            Resources res, List<InputMethodSubtype> subtypes, String mode, String locale,
30417599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            boolean canIgnoreLocaleAsLastResort) {
30428fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        if (subtypes == null || subtypes.size() == 0) {
3043cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            return null;
30448fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        }
30454e4569dab5c75804b01a19b2d6e6101b445c1c68satok        if (TextUtils.isEmpty(locale)) {
3046df31ae6a3011d47421a6ac10021f9649dc34a156satok            locale = res.getConfiguration().locale.toString();
30474e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
30488fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        final String language = locale.substring(0, 2);
30498fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        boolean partialMatchFound = false;
3050cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok        InputMethodSubtype applicableSubtype = null;
30517599a7fb1ab5b75ca801f7d7e448f4c097320e01satok        InputMethodSubtype firstMatchedModeSubtype = null;
305216331c8a1d33defccc5cbb18694def79196c921bsatok        final int N = subtypes.size();
305316331c8a1d33defccc5cbb18694def79196c921bsatok        for (int i = 0; i < N; ++i) {
3054cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            InputMethodSubtype subtype = subtypes.get(i);
3055cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            final String subtypeLocale = subtype.getLocale();
3056d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok            // An applicable subtype should match "mode". If mode is null, mode will be ignored,
3057d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok            // and all subtypes with all modes can be candidates.
3058d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok            if (mode == null || subtypes.get(i).getMode().equalsIgnoreCase(mode)) {
30597599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                if (firstMatchedModeSubtype == null) {
30607599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                    firstMatchedModeSubtype = subtype;
30617599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                }
30629ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                if (locale.equals(subtypeLocale)) {
30639ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                    // Exact match (e.g. system locale is "en_US" and subtype locale is "en_US")
3064cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    applicableSubtype = subtype;
30659ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                    break;
30669ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                } else if (!partialMatchFound && subtypeLocale.startsWith(language)) {
30679ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                    // Partial match (e.g. system locale is "en_US" and subtype locale is "en")
3068cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    applicableSubtype = subtype;
30699ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                    partialMatchFound = true;
30709ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                }
30718fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok            }
30728fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        }
30738fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok
30747599a7fb1ab5b75ca801f7d7e448f4c097320e01satok        if (applicableSubtype == null && canIgnoreLocaleAsLastResort) {
30757599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            return firstMatchedModeSubtype;
307616331c8a1d33defccc5cbb18694def79196c921bsatok        }
307716331c8a1d33defccc5cbb18694def79196c921bsatok
30788fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        // The first subtype applicable to the system locale will be defined as the most applicable
30798fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        // subtype.
30808fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        if (DEBUG) {
308116331c8a1d33defccc5cbb18694def79196c921bsatok            if (applicableSubtype != null) {
308216331c8a1d33defccc5cbb18694def79196c921bsatok                Slog.d(TAG, "Applicable InputMethodSubtype was found: "
308316331c8a1d33defccc5cbb18694def79196c921bsatok                        + applicableSubtype.getMode() + "," + applicableSubtype.getLocale());
308416331c8a1d33defccc5cbb18694def79196c921bsatok            }
30858fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        }
3086cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok        return applicableSubtype;
30878fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok    }
30888fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok
30894e4569dab5c75804b01a19b2d6e6101b445c1c68satok    // If there are no selected shortcuts, tries finding the most applicable ones.
30904e4569dab5c75804b01a19b2d6e6101b445c1c68satok    private Pair<InputMethodInfo, InputMethodSubtype>
30914e4569dab5c75804b01a19b2d6e6101b445c1c68satok            findLastResortApplicableShortcutInputMethodAndSubtypeLocked(String mode) {
30924e4569dab5c75804b01a19b2d6e6101b445c1c68satok        List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
30934e4569dab5c75804b01a19b2d6e6101b445c1c68satok        InputMethodInfo mostApplicableIMI = null;
3094cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok        InputMethodSubtype mostApplicableSubtype = null;
30954e4569dab5c75804b01a19b2d6e6101b445c1c68satok        boolean foundInSystemIME = false;
30964e4569dab5c75804b01a19b2d6e6101b445c1c68satok
30974e4569dab5c75804b01a19b2d6e6101b445c1c68satok        // Search applicable subtype for each InputMethodInfo
30984e4569dab5c75804b01a19b2d6e6101b445c1c68satok        for (InputMethodInfo imi: imis) {
30997599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            final String imiId = imi.getId();
31007599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            if (foundInSystemIME && !imiId.equals(mCurMethodId)) {
31017599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                continue;
31027599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            }
3103cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            InputMethodSubtype subtype = null;
3104df31ae6a3011d47421a6ac10021f9649dc34a156satok            final List<InputMethodSubtype> enabledSubtypes =
31054e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    getEnabledInputMethodSubtypeListLocked(imi, true);
3106df31ae6a3011d47421a6ac10021f9649dc34a156satok            // 1. Search by the current subtype's locale from enabledSubtypes.
31074e4569dab5c75804b01a19b2d6e6101b445c1c68satok            if (mCurrentSubtype != null) {
3108cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                subtype = findLastResortApplicableSubtypeLocked(
3109df31ae6a3011d47421a6ac10021f9649dc34a156satok                        mRes, enabledSubtypes, mode, mCurrentSubtype.getLocale(), false);
31104e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
3111df31ae6a3011d47421a6ac10021f9649dc34a156satok            // 2. Search by the system locale from enabledSubtypes.
3112df31ae6a3011d47421a6ac10021f9649dc34a156satok            // 3. Search the first enabled subtype matched with mode from enabledSubtypes.
3113cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            if (subtype == null) {
3114cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                subtype = findLastResortApplicableSubtypeLocked(
3115df31ae6a3011d47421a6ac10021f9649dc34a156satok                        mRes, enabledSubtypes, mode, null, true);
31167599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            }
3117a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            final ArrayList<InputMethodSubtype> overridingImplicitlyEnabledSubtypes =
3118a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                    getOverridingImplicitlyEnabledSubtypes(imi, mode);
3119a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            final ArrayList<InputMethodSubtype> subtypesForSearch =
3120a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                    overridingImplicitlyEnabledSubtypes.isEmpty()
3121a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                            ? getSubtypes(imi) : overridingImplicitlyEnabledSubtypes;
31227599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            // 4. Search by the current subtype's locale from all subtypes.
31237599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            if (subtype == null && mCurrentSubtype != null) {
31247599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                subtype = findLastResortApplicableSubtypeLocked(
3125a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                        mRes, subtypesForSearch, mode, mCurrentSubtype.getLocale(), false);
31264e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
31277599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            // 5. Search by the system locale from all subtypes.
31287599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            // 6. Search the first enabled subtype matched with mode from all subtypes.
3129cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            if (subtype == null) {
31307599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                subtype = findLastResortApplicableSubtypeLocked(
3131a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                        mRes, subtypesForSearch, mode, null, true);
31324e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
3133cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            if (subtype != null) {
31347599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                if (imiId.equals(mCurMethodId)) {
31354e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    // The current input method is the most applicable IME.
31364e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    mostApplicableIMI = imi;
3137cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    mostApplicableSubtype = subtype;
31384e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    break;
31394e4569dab5c75804b01a19b2d6e6101b445c1c68satok                } else if (!foundInSystemIME) {
31407599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                    // The system input method is 2nd applicable IME.
31414e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    mostApplicableIMI = imi;
3142cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    mostApplicableSubtype = subtype;
31437599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                    if ((imi.getServiceInfo().applicationInfo.flags
31447599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                            & ApplicationInfo.FLAG_SYSTEM) != 0) {
31457599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                        foundInSystemIME = true;
31467599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                    }
31474e4569dab5c75804b01a19b2d6e6101b445c1c68satok                }
31484e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
31494e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
31504e4569dab5c75804b01a19b2d6e6101b445c1c68satok        if (DEBUG) {
3151cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            if (mostApplicableIMI != null) {
3152cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                Slog.w(TAG, "Most applicable shortcut input method was:"
3153cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                        + mostApplicableIMI.getId());
3154cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                if (mostApplicableSubtype != null) {
3155cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    Slog.w(TAG, "Most applicable shortcut input method subtype was:"
3156cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                            + "," + mostApplicableSubtype.getMode() + ","
3157cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                            + mostApplicableSubtype.getLocale());
3158cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                }
3159cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            }
31604e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
3161cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok        if (mostApplicableIMI != null) {
31624e4569dab5c75804b01a19b2d6e6101b445c1c68satok            return new Pair<InputMethodInfo, InputMethodSubtype> (mostApplicableIMI,
3163cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    mostApplicableSubtype);
31644e4569dab5c75804b01a19b2d6e6101b445c1c68satok        } else {
31654e4569dab5c75804b01a19b2d6e6101b445c1c68satok            return null;
31664e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
31674e4569dab5c75804b01a19b2d6e6101b445c1c68satok    }
31684e4569dab5c75804b01a19b2d6e6101b445c1c68satok
3169ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    /**
3170ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * @return Return the current subtype of this input method.
3171ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     */
317242c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
3173ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    public InputMethodSubtype getCurrentInputMethodSubtype() {
31744e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // TODO: Make this work even for non-current users?
31754e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
31764e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return null;
31774e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
31784e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        synchronized (mMethodMap) {
31794e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return getCurrentInputMethodSubtypeLocked();
31804e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
31814e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    }
31824e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
31834e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    private InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
3184fdf419e81d795593e3792c9e78f33ed899ff098esatok        if (mCurMethodId == null) {
3185fdf419e81d795593e3792c9e78f33ed899ff098esatok            return null;
3186fdf419e81d795593e3792c9e78f33ed899ff098esatok        }
31874e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final boolean subtypeIsSelected =
31884e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                mSettings.getSelectedInputMethodSubtypeHashCode() != NOT_A_SUBTYPE_ID;
31894e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
31904e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (imi == null || imi.getSubtypeCount() == 0) {
31914e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return null;
31924e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
31934e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!subtypeIsSelected || mCurrentSubtype == null
31944e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                || !isValidSubtypeId(imi, mCurrentSubtype.hashCode())) {
31954e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            int subtypeId = getSelectedInputMethodSubtypeId(mCurMethodId);
31964e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (subtypeId == NOT_A_SUBTYPE_ID) {
31974e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                // If there are no selected subtypes, the framework will try to find
31984e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                // the most applicable subtype from explicitly or implicitly enabled
31994e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                // subtypes.
32004e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
32014e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        getEnabledInputMethodSubtypeListLocked(imi, true);
32024e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                // If there is only one explicitly or implicitly enabled subtype,
32034e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                // just returns it.
32044e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
32054e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
32064e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
32074e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mCurrentSubtype = findLastResortApplicableSubtypeLocked(
32084e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                            mRes, explicitlyOrImplicitlyEnabledSubtypes,
32094e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                            SUBTYPE_MODE_KEYBOARD, null, true);
32104e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    if (mCurrentSubtype == null) {
3211fdf419e81d795593e3792c9e78f33ed899ff098esatok                        mCurrentSubtype = findLastResortApplicableSubtypeLocked(
32124e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                mRes, explicitlyOrImplicitlyEnabledSubtypes, null, null,
32134e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                true);
32144e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    }
32153ef8b29fa03fe3ae1c57fd891a12afa46128fff8satok                }
32164e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            } else {
32174e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                mCurrentSubtype = getSubtypes(imi).get(subtypeId);
32188fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok            }
32198fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        }
32204e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        return mCurrentSubtype;
3221ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
3222ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
3223f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok    private void addShortcutInputMethodAndSubtypes(InputMethodInfo imi,
3224f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            InputMethodSubtype subtype) {
3225f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok        if (mShortcutInputMethodsAndSubtypes.containsKey(imi)) {
3226f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            mShortcutInputMethodsAndSubtypes.get(imi).add(subtype);
3227f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok        } else {
3228f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
3229f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            subtypes.add(subtype);
3230f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            mShortcutInputMethodsAndSubtypes.put(imi, subtypes);
3231f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok        }
3232f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok    }
3233f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok
32344e4569dab5c75804b01a19b2d6e6101b445c1c68satok    // TODO: We should change the return type from List to List<Parcelable>
3235dbf2950781ab0c4c0fc4ad9bd71b13c55ae6f471satok    @SuppressWarnings("rawtypes")
3236e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
32374e4569dab5c75804b01a19b2d6e6101b445c1c68satok    public List getShortcutInputMethodsAndSubtypes() {
32384e4569dab5c75804b01a19b2d6e6101b445c1c68satok        synchronized (mMethodMap) {
32393da922367c0dbe67b97fe97fcfca13fd93602f7asatok            ArrayList<Object> ret = new ArrayList<Object>();
3240f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            if (mShortcutInputMethodsAndSubtypes.size() == 0) {
32414e4569dab5c75804b01a19b2d6e6101b445c1c68satok                // If there are no selected shortcut subtypes, the framework will try to find
32424e4569dab5c75804b01a19b2d6e6101b445c1c68satok                // the most applicable subtype from all subtypes whose mode is
32434e4569dab5c75804b01a19b2d6e6101b445c1c68satok                // SUBTYPE_MODE_VOICE. This is an exceptional case, so we will hardcode the mode.
3244f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                Pair<InputMethodInfo, InputMethodSubtype> info =
3245f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                    findLastResortApplicableShortcutInputMethodAndSubtypeLocked(
3246f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                            SUBTYPE_MODE_VOICE);
32477599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                if (info != null) {
32483da922367c0dbe67b97fe97fcfca13fd93602f7asatok                    ret.add(info.first);
32493da922367c0dbe67b97fe97fcfca13fd93602f7asatok                    ret.add(info.second);
32507599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                }
32513da922367c0dbe67b97fe97fcfca13fd93602f7asatok                return ret;
3252f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            }
3253f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            for (InputMethodInfo imi: mShortcutInputMethodsAndSubtypes.keySet()) {
3254f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                ret.add(imi);
3255f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                for (InputMethodSubtype subtype: mShortcutInputMethodsAndSubtypes.get(imi)) {
3256f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                    ret.add(subtype);
32574e4569dab5c75804b01a19b2d6e6101b445c1c68satok                }
32584e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
3259f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            return ret;
32604e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
32614e4569dab5c75804b01a19b2d6e6101b445c1c68satok    }
32624e4569dab5c75804b01a19b2d6e6101b445c1c68satok
326342c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
3264b66d287e3003a0934d5714fbf15e554b3c814906satok    public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
32654e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // TODO: Make this work even for non-current users?
32664e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
32674e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
32684e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
3269b66d287e3003a0934d5714fbf15e554b3c814906satok        synchronized (mMethodMap) {
3270b66d287e3003a0934d5714fbf15e554b3c814906satok            if (subtype != null && mCurMethodId != null) {
3271b66d287e3003a0934d5714fbf15e554b3c814906satok                InputMethodInfo imi = mMethodMap.get(mCurMethodId);
3272b66d287e3003a0934d5714fbf15e554b3c814906satok                int subtypeId = getSubtypeIdFromHashCode(imi, subtype.hashCode());
3273b66d287e3003a0934d5714fbf15e554b3c814906satok                if (subtypeId != NOT_A_SUBTYPE_ID) {
3274b66d287e3003a0934d5714fbf15e554b3c814906satok                    setInputMethodLocked(mCurMethodId, subtypeId);
3275b66d287e3003a0934d5714fbf15e554b3c814906satok                    return true;
3276b66d287e3003a0934d5714fbf15e554b3c814906satok                }
3277b66d287e3003a0934d5714fbf15e554b3c814906satok            }
3278b66d287e3003a0934d5714fbf15e554b3c814906satok            return false;
3279b66d287e3003a0934d5714fbf15e554b3c814906satok        }
3280b66d287e3003a0934d5714fbf15e554b3c814906satok    }
3281b66d287e3003a0934d5714fbf15e554b3c814906satok
3282688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok    private static class InputMethodAndSubtypeListManager {
3283688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        private final Context mContext;
32844e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // Used to load label
3285688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        private final PackageManager mPm;
3286688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        private final InputMethodManagerService mImms;
328793d744deb167d5c681b5bb5627fd36a92f1ea79asatok        private final String mSystemLocaleStr;
3288688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        public InputMethodAndSubtypeListManager(Context context, InputMethodManagerService imms) {
3289688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            mContext = context;
3290688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            mPm = context.getPackageManager();
3291688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            mImms = imms;
32920a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            final Locale locale = context.getResources().getConfiguration().locale;
32930a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            mSystemLocaleStr = locale != null ? locale.toString() : "";
3294688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        }
3295688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok
3296688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        private final TreeMap<InputMethodInfo, List<InputMethodSubtype>> mSortedImmis =
3297688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                new TreeMap<InputMethodInfo, List<InputMethodSubtype>>(
3298688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        new Comparator<InputMethodInfo>() {
3299688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            @Override
3300688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            public int compare(InputMethodInfo imi1, InputMethodInfo imi2) {
3301688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                if (imi2 == null) return 0;
3302688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                if (imi1 == null) return 1;
3303688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                if (mPm == null) {
3304688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                    return imi1.getId().compareTo(imi2.getId());
3305688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                }
3306688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                CharSequence imiId1 = imi1.loadLabel(mPm) + "/" + imi1.getId();
3307688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                CharSequence imiId2 = imi2.loadLabel(mPm) + "/" + imi2.getId();
3308688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                return imiId1.toString().compareTo(imiId2.toString());
3309688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            }
3310688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        });
3311688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok
3312688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        public ImeSubtypeListItem getNextInputMethod(
3313688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
3314688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            if (imi == null) {
3315688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                return null;
3316688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            }
3317688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            final List<ImeSubtypeListItem> imList = getSortedInputMethodAndSubtypeList();
3318688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            if (imList.size() <= 1) {
3319688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                return null;
3320688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            }
3321688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            final int N = imList.size();
3322688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            final int currentSubtypeId = subtype != null
3323fdf419e81d795593e3792c9e78f33ed899ff098esatok                    ? getSubtypeIdFromHashCode(imi, subtype.hashCode())
3324688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    : NOT_A_SUBTYPE_ID;
3325688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            for (int i = 0; i < N; ++i) {
3326688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                final ImeSubtypeListItem isli = imList.get(i);
3327688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                if (isli.mImi.equals(imi) && isli.mSubtypeId == currentSubtypeId) {
3328688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    if (!onlyCurrentIme) {
3329688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        return imList.get((i + 1) % N);
3330688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    }
3331688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    for (int j = 0; j < N - 1; ++j) {
3332688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        final ImeSubtypeListItem candidate = imList.get((i + j + 1) % N);
3333688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        if (candidate.mImi.equals(imi)) {
3334688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            return candidate;
3335688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        }
3336688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    }
3337688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    return null;
3338688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                }
3339688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            }
3340688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            return null;
3341688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        }
3342688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok
3343688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList() {
3344688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            return getSortedInputMethodAndSubtypeList(true, false, false);
3345688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        }
3346688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok
3347688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList(boolean showSubtypes,
3348688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                boolean inputShown, boolean isScreenLocked) {
3349688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            final ArrayList<ImeSubtypeListItem> imList = new ArrayList<ImeSubtypeListItem>();
3350688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            final HashMap<InputMethodInfo, List<InputMethodSubtype>> immis =
3351688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    mImms.getExplicitlyOrImplicitlyEnabledInputMethodsAndSubtypeListLocked();
3352688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            if (immis == null || immis.size() == 0) {
3353688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                return Collections.emptyList();
3354688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            }
3355688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            mSortedImmis.clear();
3356688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            mSortedImmis.putAll(immis);
3357688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            for (InputMethodInfo imi : mSortedImmis.keySet()) {
3358688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                if (imi == null) continue;
3359688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList = immis.get(imi);
3360688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                HashSet<String> enabledSubtypeSet = new HashSet<String>();
3361688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                for (InputMethodSubtype subtype: explicitlyOrImplicitlyEnabledSubtypeList) {
3362688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
3363688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                }
3364688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                ArrayList<InputMethodSubtype> subtypes = getSubtypes(imi);
3365688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                final CharSequence imeLabel = imi.loadLabel(mPm);
3366688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                if (showSubtypes && enabledSubtypeSet.size() > 0) {
3367688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    final int subtypeCount = imi.getSubtypeCount();
3368688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    if (DEBUG) {
3369688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
3370688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    }
3371688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    for (int j = 0; j < subtypeCount; ++j) {
3372688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        final InputMethodSubtype subtype = imi.getSubtypeAt(j);
3373688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        final String subtypeHashCode = String.valueOf(subtype.hashCode());
3374688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        // We show all enabled IMEs and subtypes when an IME is shown.
3375688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        if (enabledSubtypeSet.contains(subtypeHashCode)
3376688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                && ((inputShown && !isScreenLocked) || !subtype.isAuxiliary())) {
3377688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            final CharSequence subtypeLabel =
3378688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                    subtype.overridesImplicitlyEnabledSubtype() ? null
3379688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                            : subtype.getDisplayName(mContext, imi.getPackageName(),
3380688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                                    imi.getServiceInfo().applicationInfo);
338193d744deb167d5c681b5bb5627fd36a92f1ea79asatok                            imList.add(new ImeSubtypeListItem(imeLabel, subtypeLabel, imi, j,
338293d744deb167d5c681b5bb5627fd36a92f1ea79asatok                                    subtype.getLocale(), mSystemLocaleStr));
3383688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok
3384688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            // Removing this subtype from enabledSubtypeSet because we no longer
3385688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            // need to add an entry of this subtype to imList to avoid duplicated
3386688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            // entries.
3387688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            enabledSubtypeSet.remove(subtypeHashCode);
3388688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        }
3389688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    }
3390688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                } else {
339193d744deb167d5c681b5bb5627fd36a92f1ea79asatok                    imList.add(new ImeSubtypeListItem(imeLabel, null, imi, NOT_A_SUBTYPE_ID,
339293d744deb167d5c681b5bb5627fd36a92f1ea79asatok                            null, mSystemLocaleStr));
3393688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                }
3394688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            }
339593d744deb167d5c681b5bb5627fd36a92f1ea79asatok            Collections.sort(imList);
3396688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            return imList;
3397688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        }
3398688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok    }
3399688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok
3400d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    /**
3401d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok     * Utility class for putting and getting settings for InputMethod
3402d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok     * TODO: Move all putters and getters of settings to this class.
3403d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok     */
3404d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    private static class InputMethodSettings {
3405d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // The string for enabled input method is saved as follows:
3406d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // example: ("ime0;subtype0;subtype1;subtype2:ime1:ime2;subtype0")
3407d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private static final char INPUT_METHOD_SEPARATER = ':';
3408d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private static final char INPUT_METHOD_SUBTYPE_SEPARATER = ';';
3409723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private final TextUtils.SimpleStringSplitter mInputMethodSplitter =
3410d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATER);
3411d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3412723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private final TextUtils.SimpleStringSplitter mSubtypeSplitter =
3413d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATER);
3414d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3415df31ae6a3011d47421a6ac10021f9649dc34a156satok        private final Resources mRes;
3416d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private final ContentResolver mResolver;
3417d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private final HashMap<String, InputMethodInfo> mMethodMap;
3418d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private final ArrayList<InputMethodInfo> mMethodList;
3419d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3420d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private String mEnabledInputMethodsStrCache;
34214e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        private int mCurrentUserId;
3422d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3423d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private static void buildEnabledInputMethodsSettingString(
3424d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                StringBuilder builder, Pair<String, ArrayList<String>> pair) {
3425d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            String id = pair.first;
3426d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            ArrayList<String> subtypes = pair.second;
3427d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            builder.append(id);
342857c767c7b7a4cdcd0c33ec453a9f2c0b853999b6satok            // Inputmethod and subtypes are saved in the settings as follows:
342957c767c7b7a4cdcd0c33ec453a9f2c0b853999b6satok            // ime0;subtype0;subtype1:ime1;subtype0:ime2:ime3;subtype0;subtype1
343057c767c7b7a4cdcd0c33ec453a9f2c0b853999b6satok            for (String subtypeId: subtypes) {
343157c767c7b7a4cdcd0c33ec453a9f2c0b853999b6satok                builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypeId);
3432d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3433d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3434d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3435d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public InputMethodSettings(
3436df31ae6a3011d47421a6ac10021f9649dc34a156satok                Resources res, ContentResolver resolver,
34374e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
34384e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                int userId) {
34394e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            setCurrentUserId(userId);
3440df31ae6a3011d47421a6ac10021f9649dc34a156satok            mRes = res;
3441d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mResolver = resolver;
3442d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mMethodMap = methodMap;
3443d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mMethodList = methodList;
3444d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3445d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
34464e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        public void setCurrentUserId(int userId) {
34474e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
34484e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "--- Swtich the current user from " + mCurrentUserId + " to "
34494e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        + userId + ", new ime = " + getSelectedInputMethod());
34504e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
34514e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            // IMMS settings are kept per user, so keep track of current user
34524e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            mCurrentUserId = userId;
34534e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
34544e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
3455d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public List<InputMethodInfo> getEnabledInputMethodListLocked() {
3456d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return createEnabledInputMethodListLocked(
3457d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    getEnabledInputMethodsAndSubtypeListLocked());
3458d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3459d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
34607f35c8cc88bea5230f001dd4356f864845d202e5satok        public List<Pair<InputMethodInfo, ArrayList<String>>>
346167ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                getEnabledInputMethodAndSubtypeHashCodeListLocked() {
346267ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            return createEnabledInputMethodAndSubtypeHashCodeListLocked(
34637f35c8cc88bea5230f001dd4356f864845d202e5satok                    getEnabledInputMethodsAndSubtypeListLocked());
34647f35c8cc88bea5230f001dd4356f864845d202e5satok        }
34657f35c8cc88bea5230f001dd4356f864845d202e5satok
346667ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok        public List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(
346767ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                InputMethodInfo imi) {
346867ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            List<Pair<String, ArrayList<String>>> imsList =
346967ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                    getEnabledInputMethodsAndSubtypeListLocked();
347067ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            ArrayList<InputMethodSubtype> enabledSubtypes =
347167ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                    new ArrayList<InputMethodSubtype>();
3472884ef9a11fb25b80630265daee46c5609707751fsatok            if (imi != null) {
3473884ef9a11fb25b80630265daee46c5609707751fsatok                for (Pair<String, ArrayList<String>> imsPair : imsList) {
3474884ef9a11fb25b80630265daee46c5609707751fsatok                    InputMethodInfo info = mMethodMap.get(imsPair.first);
3475884ef9a11fb25b80630265daee46c5609707751fsatok                    if (info != null && info.getId().equals(imi.getId())) {
3476586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                        final int subtypeCount = info.getSubtypeCount();
3477586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                        for (int i = 0; i < subtypeCount; ++i) {
3478586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                            InputMethodSubtype ims = info.getSubtypeAt(i);
3479884ef9a11fb25b80630265daee46c5609707751fsatok                            for (String s: imsPair.second) {
3480884ef9a11fb25b80630265daee46c5609707751fsatok                                if (String.valueOf(ims.hashCode()).equals(s)) {
3481884ef9a11fb25b80630265daee46c5609707751fsatok                                    enabledSubtypes.add(ims);
3482884ef9a11fb25b80630265daee46c5609707751fsatok                                }
348367ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                            }
348467ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                        }
3485884ef9a11fb25b80630265daee46c5609707751fsatok                        break;
348667ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                    }
348767ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                }
348867ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            }
348967ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            return enabledSubtypes;
349067ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok        }
349167ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok
3492d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // At the initial boot, the settings for input methods are not set,
3493d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // so we need to enable IME in that case.
3494d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public void enableAllIMEsIfThereIsNoEnabledIME() {
3495d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (TextUtils.isEmpty(getEnabledInputMethodsStr())) {
3496d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                StringBuilder sb = new StringBuilder();
3497d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                final int N = mMethodList.size();
3498d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                for (int i = 0; i < N; i++) {
3499d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    InputMethodInfo imi = mMethodList.get(i);
3500d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    Slog.i(TAG, "Adding: " + imi.getId());
3501d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    if (i > 0) sb.append(':');
3502d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    sb.append(imi.getId());
3503d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
3504d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                putEnabledInputMethodsStr(sb.toString());
3505d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3506d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3507d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3508bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        private List<Pair<String, ArrayList<String>>> getEnabledInputMethodsAndSubtypeListLocked() {
3509d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            ArrayList<Pair<String, ArrayList<String>>> imsList
3510d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    = new ArrayList<Pair<String, ArrayList<String>>>();
3511d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            final String enabledInputMethodsStr = getEnabledInputMethodsStr();
3512d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (TextUtils.isEmpty(enabledInputMethodsStr)) {
3513d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                return imsList;
3514d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3515723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mInputMethodSplitter.setString(enabledInputMethodsStr);
3516723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            while (mInputMethodSplitter.hasNext()) {
3517723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                String nextImsStr = mInputMethodSplitter.next();
3518723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                mSubtypeSplitter.setString(nextImsStr);
3519723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (mSubtypeSplitter.hasNext()) {
3520d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    ArrayList<String> subtypeHashes = new ArrayList<String>();
3521d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // The first element is ime id.
3522723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    String imeId = mSubtypeSplitter.next();
3523723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    while (mSubtypeSplitter.hasNext()) {
3524723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        subtypeHashes.add(mSubtypeSplitter.next());
3525d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    }
3526d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    imsList.add(new Pair<String, ArrayList<String>>(imeId, subtypeHashes));
3527d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
3528d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3529d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return imsList;
3530d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3531d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3532d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public void appendAndPutEnabledInputMethodLocked(String id, boolean reloadInputMethodStr) {
3533d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (reloadInputMethodStr) {
3534d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                getEnabledInputMethodsStr();
3535d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3536d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (TextUtils.isEmpty(mEnabledInputMethodsStrCache)) {
3537d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Add in the newly enabled input method.
3538d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                putEnabledInputMethodsStr(id);
3539d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            } else {
3540d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                putEnabledInputMethodsStr(
3541d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                        mEnabledInputMethodsStrCache + INPUT_METHOD_SEPARATER + id);
3542d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3543d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3544d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3545d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        /**
3546d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok         * Build and put a string of EnabledInputMethods with removing specified Id.
3547d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok         * @return the specified id was removed or not.
3548d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok         */
3549d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public boolean buildAndPutEnabledInputMethodsStrRemovingIdLocked(
3550d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                StringBuilder builder, List<Pair<String, ArrayList<String>>> imsList, String id) {
3551d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            boolean isRemoved = false;
3552d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            boolean needsAppendSeparator = false;
3553d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            for (Pair<String, ArrayList<String>> ims: imsList) {
3554d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                String curId = ims.first;
3555d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                if (curId.equals(id)) {
3556d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // We are disabling this input method, and it is
3557d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // currently enabled.  Skip it to remove from the
3558d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // new list.
3559d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    isRemoved = true;
3560d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                } else {
3561d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    if (needsAppendSeparator) {
3562d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                        builder.append(INPUT_METHOD_SEPARATER);
3563d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    } else {
3564d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                        needsAppendSeparator = true;
3565d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    }
3566d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    buildEnabledInputMethodsSettingString(builder, ims);
3567d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
3568d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3569d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (isRemoved) {
3570d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Update the setting with the new list of input methods.
3571d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                putEnabledInputMethodsStr(builder.toString());
3572d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3573d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return isRemoved;
3574d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3575d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3576d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private List<InputMethodInfo> createEnabledInputMethodListLocked(
3577d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                List<Pair<String, ArrayList<String>>> imsList) {
3578d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            final ArrayList<InputMethodInfo> res = new ArrayList<InputMethodInfo>();
3579d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            for (Pair<String, ArrayList<String>> ims: imsList) {
3580d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                InputMethodInfo info = mMethodMap.get(ims.first);
3581d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                if (info != null) {
3582d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    res.add(info);
3583d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
3584d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3585d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return res;
3586d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3587d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
35887f35c8cc88bea5230f001dd4356f864845d202e5satok        private List<Pair<InputMethodInfo, ArrayList<String>>>
358967ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                createEnabledInputMethodAndSubtypeHashCodeListLocked(
35907f35c8cc88bea5230f001dd4356f864845d202e5satok                        List<Pair<String, ArrayList<String>>> imsList) {
35917f35c8cc88bea5230f001dd4356f864845d202e5satok            final ArrayList<Pair<InputMethodInfo, ArrayList<String>>> res
35927f35c8cc88bea5230f001dd4356f864845d202e5satok                    = new ArrayList<Pair<InputMethodInfo, ArrayList<String>>>();
35937f35c8cc88bea5230f001dd4356f864845d202e5satok            for (Pair<String, ArrayList<String>> ims : imsList) {
35947f35c8cc88bea5230f001dd4356f864845d202e5satok                InputMethodInfo info = mMethodMap.get(ims.first);
35957f35c8cc88bea5230f001dd4356f864845d202e5satok                if (info != null) {
35967f35c8cc88bea5230f001dd4356f864845d202e5satok                    res.add(new Pair<InputMethodInfo, ArrayList<String>>(info, ims.second));
35977f35c8cc88bea5230f001dd4356f864845d202e5satok                }
35987f35c8cc88bea5230f001dd4356f864845d202e5satok            }
35997f35c8cc88bea5230f001dd4356f864845d202e5satok            return res;
36007f35c8cc88bea5230f001dd4356f864845d202e5satok        }
36017f35c8cc88bea5230f001dd4356f864845d202e5satok
3602d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private void putEnabledInputMethodsStr(String str) {
36034e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Settings.Secure.putStringForUser(
36044e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mResolver, Settings.Secure.ENABLED_INPUT_METHODS, str, mCurrentUserId);
3605d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mEnabledInputMethodsStrCache = str;
36064e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
36074e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "putEnabledInputMethodStr: " + str);
36084e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
3609d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3610d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3611d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private String getEnabledInputMethodsStr() {
36124e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            mEnabledInputMethodsStrCache = Settings.Secure.getStringForUser(
36134e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mResolver, Settings.Secure.ENABLED_INPUT_METHODS, mCurrentUserId);
3614723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (DEBUG) {
36154e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "getEnabledInputMethodsStr: " + mEnabledInputMethodsStrCache
36164e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        + ", " + mCurrentUserId);
3617723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3618d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return mEnabledInputMethodsStrCache;
3619d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3620723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3621723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private void saveSubtypeHistory(
3622723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                List<Pair<String, String>> savedImes, String newImeId, String newSubtypeId) {
3623723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            StringBuilder builder = new StringBuilder();
3624723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            boolean isImeAdded = false;
3625723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (!TextUtils.isEmpty(newImeId) && !TextUtils.isEmpty(newSubtypeId)) {
3626723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                builder.append(newImeId).append(INPUT_METHOD_SUBTYPE_SEPARATER).append(
3627723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        newSubtypeId);
3628723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                isImeAdded = true;
3629723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3630723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            for (Pair<String, String> ime: savedImes) {
3631723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                String imeId = ime.first;
3632723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                String subtypeId = ime.second;
3633723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (TextUtils.isEmpty(subtypeId)) {
3634723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    subtypeId = NOT_A_SUBTYPE_ID_STR;
3635723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
3636723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (isImeAdded) {
3637723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    builder.append(INPUT_METHOD_SEPARATER);
3638723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                } else {
3639723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    isImeAdded = true;
3640723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
3641723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                builder.append(imeId).append(INPUT_METHOD_SUBTYPE_SEPARATER).append(
3642723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        subtypeId);
3643723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3644723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // Remove the last INPUT_METHOD_SEPARATER
3645723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            putSubtypeHistoryStr(builder.toString());
3646723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3647723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3648723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public void addSubtypeToHistory(String imeId, String subtypeId) {
3649723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            List<Pair<String, String>> subtypeHistory = loadInputMethodAndSubtypeHistoryLocked();
3650723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            for (Pair<String, String> ime: subtypeHistory) {
3651723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (ime.first.equals(imeId)) {
3652723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    if (DEBUG) {
3653bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                        Slog.v(TAG, "Subtype found in the history: " + imeId + ", "
3654723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                                + ime.second);
3655723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    }
3656723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    // We should break here
3657723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    subtypeHistory.remove(ime);
3658723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    break;
3659723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
3660723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3661bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            if (DEBUG) {
3662bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                Slog.v(TAG, "Add subtype to the history: " + imeId + ", " + subtypeId);
3663bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            }
3664723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            saveSubtypeHistory(subtypeHistory, imeId, subtypeId);
3665723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3666723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3667723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private void putSubtypeHistoryStr(String str) {
3668723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (DEBUG) {
3669723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                Slog.d(TAG, "putSubtypeHistoryStr: " + str);
3670723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
36714e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Settings.Secure.putStringForUser(
36724e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, str, mCurrentUserId);
3673723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3674723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3675723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public Pair<String, String> getLastInputMethodAndSubtypeLocked() {
3676723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // Gets the first one from the history
3677723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            return getLastSubtypeForInputMethodLockedInternal(null);
3678723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3679723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3680723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public String getLastSubtypeForInputMethodLocked(String imeId) {
3681723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            Pair<String, String> ime = getLastSubtypeForInputMethodLockedInternal(imeId);
3682723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (ime != null) {
3683723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                return ime.second;
3684723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            } else {
3685723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                return null;
3686723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3687723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3688723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3689723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private Pair<String, String> getLastSubtypeForInputMethodLockedInternal(String imeId) {
3690723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            List<Pair<String, ArrayList<String>>> enabledImes =
3691723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    getEnabledInputMethodsAndSubtypeListLocked();
3692723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            List<Pair<String, String>> subtypeHistory = loadInputMethodAndSubtypeHistoryLocked();
36934fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            for (Pair<String, String> imeAndSubtype : subtypeHistory) {
3694723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                final String imeInTheHistory = imeAndSubtype.first;
3695723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                // If imeId is empty, returns the first IME and subtype in the history
3696723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (TextUtils.isEmpty(imeId) || imeInTheHistory.equals(imeId)) {
3697723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    final String subtypeInTheHistory = imeAndSubtype.second;
3698df31ae6a3011d47421a6ac10021f9649dc34a156satok                    final String subtypeHashCode =
3699df31ae6a3011d47421a6ac10021f9649dc34a156satok                            getEnabledSubtypeHashCodeForInputMethodAndSubtypeLocked(
3700df31ae6a3011d47421a6ac10021f9649dc34a156satok                                    enabledImes, imeInTheHistory, subtypeInTheHistory);
3701723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    if (!TextUtils.isEmpty(subtypeHashCode)) {
3702723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        if (DEBUG) {
3703bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                            Slog.d(TAG, "Enabled subtype found in the history: " + subtypeHashCode);
3704723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        }
3705723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        return new Pair<String, String>(imeInTheHistory, subtypeHashCode);
3706723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    }
3707723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
3708723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3709723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (DEBUG) {
3710723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                Slog.d(TAG, "No enabled IME found in the history");
3711723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3712723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            return null;
3713723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3714723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3715df31ae6a3011d47421a6ac10021f9649dc34a156satok        private String getEnabledSubtypeHashCodeForInputMethodAndSubtypeLocked(List<Pair<String,
3716723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                ArrayList<String>>> enabledImes, String imeId, String subtypeHashCode) {
3717723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            for (Pair<String, ArrayList<String>> enabledIme: enabledImes) {
3718723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (enabledIme.first.equals(imeId)) {
3719f6cafb63753a26440cb3ad2e5124370aef650015satok                    final ArrayList<String> explicitlyEnabledSubtypes = enabledIme.second;
3720fdf419e81d795593e3792c9e78f33ed899ff098esatok                    final InputMethodInfo imi = mMethodMap.get(imeId);
3721f6cafb63753a26440cb3ad2e5124370aef650015satok                    if (explicitlyEnabledSubtypes.size() == 0) {
3722f6cafb63753a26440cb3ad2e5124370aef650015satok                        // If there are no explicitly enabled subtypes, applicable subtypes are
3723f6cafb63753a26440cb3ad2e5124370aef650015satok                        // enabled implicitly.
3724df31ae6a3011d47421a6ac10021f9649dc34a156satok                        // If IME is enabled and no subtypes are enabled, applicable subtypes
3725df31ae6a3011d47421a6ac10021f9649dc34a156satok                        // are enabled implicitly, so needs to treat them to be enabled.
3726a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                        if (imi != null && imi.getSubtypeCount() > 0) {
3727df31ae6a3011d47421a6ac10021f9649dc34a156satok                            List<InputMethodSubtype> implicitlySelectedSubtypes =
3728a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                                    getImplicitlyApplicableSubtypesLocked(mRes, imi);
3729df31ae6a3011d47421a6ac10021f9649dc34a156satok                            if (implicitlySelectedSubtypes != null) {
3730df31ae6a3011d47421a6ac10021f9649dc34a156satok                                final int N = implicitlySelectedSubtypes.size();
3731df31ae6a3011d47421a6ac10021f9649dc34a156satok                                for (int i = 0; i < N; ++i) {
3732df31ae6a3011d47421a6ac10021f9649dc34a156satok                                    final InputMethodSubtype st = implicitlySelectedSubtypes.get(i);
3733df31ae6a3011d47421a6ac10021f9649dc34a156satok                                    if (String.valueOf(st.hashCode()).equals(subtypeHashCode)) {
3734df31ae6a3011d47421a6ac10021f9649dc34a156satok                                        return subtypeHashCode;
3735df31ae6a3011d47421a6ac10021f9649dc34a156satok                                    }
3736df31ae6a3011d47421a6ac10021f9649dc34a156satok                                }
3737df31ae6a3011d47421a6ac10021f9649dc34a156satok                            }
3738df31ae6a3011d47421a6ac10021f9649dc34a156satok                        }
3739df31ae6a3011d47421a6ac10021f9649dc34a156satok                    } else {
3740f6cafb63753a26440cb3ad2e5124370aef650015satok                        for (String s: explicitlyEnabledSubtypes) {
3741df31ae6a3011d47421a6ac10021f9649dc34a156satok                            if (s.equals(subtypeHashCode)) {
3742df31ae6a3011d47421a6ac10021f9649dc34a156satok                                // If both imeId and subtypeId are enabled, return subtypeId.
3743fdf419e81d795593e3792c9e78f33ed899ff098esatok                                try {
3744fdf419e81d795593e3792c9e78f33ed899ff098esatok                                    final int hashCode = Integer.valueOf(subtypeHashCode);
3745fdf419e81d795593e3792c9e78f33ed899ff098esatok                                    // Check whether the subtype id is valid or not
3746fdf419e81d795593e3792c9e78f33ed899ff098esatok                                    if (isValidSubtypeId(imi, hashCode)) {
3747fdf419e81d795593e3792c9e78f33ed899ff098esatok                                        return s;
3748fdf419e81d795593e3792c9e78f33ed899ff098esatok                                    } else {
3749fdf419e81d795593e3792c9e78f33ed899ff098esatok                                        return NOT_A_SUBTYPE_ID_STR;
3750fdf419e81d795593e3792c9e78f33ed899ff098esatok                                    }
3751fdf419e81d795593e3792c9e78f33ed899ff098esatok                                } catch (NumberFormatException e) {
3752fdf419e81d795593e3792c9e78f33ed899ff098esatok                                    return NOT_A_SUBTYPE_ID_STR;
3753fdf419e81d795593e3792c9e78f33ed899ff098esatok                                }
3754df31ae6a3011d47421a6ac10021f9649dc34a156satok                            }
3755723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        }
3756723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    }
3757723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    // If imeId was enabled but subtypeId was disabled.
3758723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    return NOT_A_SUBTYPE_ID_STR;
3759723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
3760723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3761723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // If both imeId and subtypeId are disabled, return null
3762723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            return null;
3763723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3764723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3765723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private List<Pair<String, String>> loadInputMethodAndSubtypeHistoryLocked() {
3766723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            ArrayList<Pair<String, String>> imsList = new ArrayList<Pair<String, String>>();
3767723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            final String subtypeHistoryStr = getSubtypeHistoryStr();
3768723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (TextUtils.isEmpty(subtypeHistoryStr)) {
3769723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                return imsList;
3770723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3771723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mInputMethodSplitter.setString(subtypeHistoryStr);
3772723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            while (mInputMethodSplitter.hasNext()) {
3773723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                String nextImsStr = mInputMethodSplitter.next();
3774723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                mSubtypeSplitter.setString(nextImsStr);
3775723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (mSubtypeSplitter.hasNext()) {
3776723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    String subtypeId = NOT_A_SUBTYPE_ID_STR;
3777723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    // The first element is ime id.
3778723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    String imeId = mSubtypeSplitter.next();
3779723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    while (mSubtypeSplitter.hasNext()) {
3780723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        subtypeId = mSubtypeSplitter.next();
3781723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        break;
3782723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    }
3783723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    imsList.add(new Pair<String, String>(imeId, subtypeId));
3784723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
3785723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3786723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            return imsList;
3787723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3788723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3789723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private String getSubtypeHistoryStr() {
3790723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (DEBUG) {
37914e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "getSubtypeHistoryStr: " + Settings.Secure.getStringForUser(
37924e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, mCurrentUserId));
3793723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
37944e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return Settings.Secure.getStringForUser(
37954e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, mCurrentUserId);
3796723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3797723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3798723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public void putSelectedInputMethod(String imeId) {
37994e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
38004e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "putSelectedInputMethodStr: " + imeId + ", "
38014e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        + mCurrentUserId);
38024e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
38034e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Settings.Secure.putStringForUser(
38044e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mResolver, Settings.Secure.DEFAULT_INPUT_METHOD, imeId, mCurrentUserId);
3805723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3806723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3807723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public void putSelectedSubtype(int subtypeId) {
38084e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
38094e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "putSelectedInputMethodSubtypeStr: " + subtypeId + ", "
38104e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        + mCurrentUserId);
38114e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
38124e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Settings.Secure.putIntForUser(mResolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
38134e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    subtypeId, mCurrentUserId);
38144e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
38154e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
38164e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        public String getDisabledSystemInputMethods() {
38174e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return Settings.Secure.getStringForUser(
38184e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mResolver, Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, mCurrentUserId);
38194e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
38204e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
38214e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        public String getSelectedInputMethod() {
38224e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
38234e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "getSelectedInputMethodStr: " + Settings.Secure.getStringForUser(
38244e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        mResolver, Settings.Secure.DEFAULT_INPUT_METHOD, mCurrentUserId)
38254e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        + ", " + mCurrentUserId);
38264e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
38274e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return Settings.Secure.getStringForUser(
38284e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mResolver, Settings.Secure.DEFAULT_INPUT_METHOD, mCurrentUserId);
38294e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
38304e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
38314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        public int getSelectedInputMethodSubtypeHashCode() {
38324e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            try {
38334e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                return Settings.Secure.getIntForUser(
38344e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        mResolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, mCurrentUserId);
38354e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            } catch (SettingNotFoundException e) {
38364e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                return NOT_A_SUBTYPE_ID;
38374e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
38384e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
38394e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
38404e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        public int getCurrentUserId() {
38414e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return mCurrentUserId;
3842723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3843d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    }
3844d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
38455ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka    // TODO: Cache the state for each user and reset when the cached user is removed.
3846e7c6998e0a953ae55487d4fe122739646f9280aasatok    private static class InputMethodFileManager {
3847e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String SYSTEM_PATH = "system";
3848e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String INPUT_METHOD_PATH = "inputmethod";
3849e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ADDITIONAL_SUBTYPES_FILE_NAME = "subtypes.xml";
3850e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String NODE_SUBTYPES = "subtypes";
3851e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String NODE_SUBTYPE = "subtype";
3852e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String NODE_IMI = "imi";
3853e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ATTR_ID = "id";
3854e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ATTR_LABEL = "label";
3855e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ATTR_ICON = "icon";
3856e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ATTR_IME_SUBTYPE_LOCALE = "imeSubtypeLocale";
3857e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ATTR_IME_SUBTYPE_MODE = "imeSubtypeMode";
3858e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ATTR_IME_SUBTYPE_EXTRA_VALUE = "imeSubtypeExtraValue";
3859e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ATTR_IS_AUXILIARY = "isAuxiliary";
3860e7c6998e0a953ae55487d4fe122739646f9280aasatok        private final AtomicFile mAdditionalInputMethodSubtypeFile;
3861e7c6998e0a953ae55487d4fe122739646f9280aasatok        private final HashMap<String, InputMethodInfo> mMethodMap;
3862e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka        private final HashMap<String, List<InputMethodSubtype>> mAdditionalSubtypesMap =
3863e7c6998e0a953ae55487d4fe122739646f9280aasatok                new HashMap<String, List<InputMethodSubtype>>();
38645ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka        public InputMethodFileManager(HashMap<String, InputMethodInfo> methodMap, int userId) {
3865e7c6998e0a953ae55487d4fe122739646f9280aasatok            if (methodMap == null) {
3866e7c6998e0a953ae55487d4fe122739646f9280aasatok                throw new NullPointerException("methodMap is null");
3867e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
3868e7c6998e0a953ae55487d4fe122739646f9280aasatok            mMethodMap = methodMap;
38695ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka            final File systemDir = userId == UserHandle.USER_OWNER
38705ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka                    ? new File(Environment.getDataDirectory(), SYSTEM_PATH)
38715ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka                    : Environment.getUserSystemDirectory(userId);
3872e7c6998e0a953ae55487d4fe122739646f9280aasatok            final File inputMethodDir = new File(systemDir, INPUT_METHOD_PATH);
3873e7c6998e0a953ae55487d4fe122739646f9280aasatok            if (!inputMethodDir.mkdirs()) {
3874e7c6998e0a953ae55487d4fe122739646f9280aasatok                Slog.w(TAG, "Couldn't create dir.: " + inputMethodDir.getAbsolutePath());
3875e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
3876e7c6998e0a953ae55487d4fe122739646f9280aasatok            final File subtypeFile = new File(inputMethodDir, ADDITIONAL_SUBTYPES_FILE_NAME);
3877e7c6998e0a953ae55487d4fe122739646f9280aasatok            mAdditionalInputMethodSubtypeFile = new AtomicFile(subtypeFile);
3878e7c6998e0a953ae55487d4fe122739646f9280aasatok            if (!subtypeFile.exists()) {
3879e7c6998e0a953ae55487d4fe122739646f9280aasatok                // If "subtypes.xml" doesn't exist, create a blank file.
3880e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                writeAdditionalInputMethodSubtypes(
3881e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                        mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, methodMap);
3882e7c6998e0a953ae55487d4fe122739646f9280aasatok            } else {
3883e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                readAdditionalInputMethodSubtypes(
3884e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                        mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile);
3885e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
3886e7c6998e0a953ae55487d4fe122739646f9280aasatok        }
3887e7c6998e0a953ae55487d4fe122739646f9280aasatok
3888e7c6998e0a953ae55487d4fe122739646f9280aasatok        private void deleteAllInputMethodSubtypes(String imiId) {
3889e7c6998e0a953ae55487d4fe122739646f9280aasatok            synchronized (mMethodMap) {
3890e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                mAdditionalSubtypesMap.remove(imiId);
3891e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                writeAdditionalInputMethodSubtypes(
3892e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                        mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, mMethodMap);
3893e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
3894e7c6998e0a953ae55487d4fe122739646f9280aasatok        }
3895e7c6998e0a953ae55487d4fe122739646f9280aasatok
3896e7c6998e0a953ae55487d4fe122739646f9280aasatok        public void addInputMethodSubtypes(
38974a28bde70e23b2ed151d52690da702da7f23cf5esatok                InputMethodInfo imi, InputMethodSubtype[] additionalSubtypes) {
3898e7c6998e0a953ae55487d4fe122739646f9280aasatok            synchronized (mMethodMap) {
3899e7c6998e0a953ae55487d4fe122739646f9280aasatok                final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
3900e7c6998e0a953ae55487d4fe122739646f9280aasatok                final int N = additionalSubtypes.length;
3901e7c6998e0a953ae55487d4fe122739646f9280aasatok                for (int i = 0; i < N; ++i) {
3902e7c6998e0a953ae55487d4fe122739646f9280aasatok                    final InputMethodSubtype subtype = additionalSubtypes[i];
3903ed2b24ecc7842b27178fc584a9e5bd5b1ab07635satok                    if (!subtypes.contains(subtype)) {
3904e7c6998e0a953ae55487d4fe122739646f9280aasatok                        subtypes.add(subtype);
3905e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                    } else {
3906e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                        Slog.w(TAG, "Duplicated subtype definition found: "
3907e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                                + subtype.getLocale() + ", " + subtype.getMode());
3908e7c6998e0a953ae55487d4fe122739646f9280aasatok                    }
3909e7c6998e0a953ae55487d4fe122739646f9280aasatok                }
3910e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                mAdditionalSubtypesMap.put(imi.getId(), subtypes);
3911e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                writeAdditionalInputMethodSubtypes(
3912e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                        mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, mMethodMap);
3913e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
3914e7c6998e0a953ae55487d4fe122739646f9280aasatok        }
3915e7c6998e0a953ae55487d4fe122739646f9280aasatok
3916e7c6998e0a953ae55487d4fe122739646f9280aasatok        public HashMap<String, List<InputMethodSubtype>> getAllAdditionalInputMethodSubtypes() {
3917e7c6998e0a953ae55487d4fe122739646f9280aasatok            synchronized (mMethodMap) {
3918e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                return mAdditionalSubtypesMap;
3919e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
3920e7c6998e0a953ae55487d4fe122739646f9280aasatok        }
3921e7c6998e0a953ae55487d4fe122739646f9280aasatok
3922e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static void writeAdditionalInputMethodSubtypes(
3923e7c6998e0a953ae55487d4fe122739646f9280aasatok                HashMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile,
3924e7c6998e0a953ae55487d4fe122739646f9280aasatok                HashMap<String, InputMethodInfo> methodMap) {
3925e7c6998e0a953ae55487d4fe122739646f9280aasatok            // Safety net for the case that this function is called before methodMap is set.
3926e7c6998e0a953ae55487d4fe122739646f9280aasatok            final boolean isSetMethodMap = methodMap != null && methodMap.size() > 0;
3927e7c6998e0a953ae55487d4fe122739646f9280aasatok            FileOutputStream fos = null;
3928e7c6998e0a953ae55487d4fe122739646f9280aasatok            try {
3929e7c6998e0a953ae55487d4fe122739646f9280aasatok                fos = subtypesFile.startWrite();
3930e7c6998e0a953ae55487d4fe122739646f9280aasatok                final XmlSerializer out = new FastXmlSerializer();
3931e7c6998e0a953ae55487d4fe122739646f9280aasatok                out.setOutput(fos, "utf-8");
3932e7c6998e0a953ae55487d4fe122739646f9280aasatok                out.startDocument(null, true);
3933e7c6998e0a953ae55487d4fe122739646f9280aasatok                out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
3934e7c6998e0a953ae55487d4fe122739646f9280aasatok                out.startTag(null, NODE_SUBTYPES);
3935e7c6998e0a953ae55487d4fe122739646f9280aasatok                for (String imiId : allSubtypes.keySet()) {
3936e7c6998e0a953ae55487d4fe122739646f9280aasatok                    if (isSetMethodMap && !methodMap.containsKey(imiId)) {
3937e7c6998e0a953ae55487d4fe122739646f9280aasatok                        Slog.w(TAG, "IME uninstalled or not valid.: " + imiId);
3938e7c6998e0a953ae55487d4fe122739646f9280aasatok                        continue;
3939e7c6998e0a953ae55487d4fe122739646f9280aasatok                    }
3940e7c6998e0a953ae55487d4fe122739646f9280aasatok                    out.startTag(null, NODE_IMI);
3941e7c6998e0a953ae55487d4fe122739646f9280aasatok                    out.attribute(null, ATTR_ID, imiId);
3942e7c6998e0a953ae55487d4fe122739646f9280aasatok                    final List<InputMethodSubtype> subtypesList = allSubtypes.get(imiId);
3943e7c6998e0a953ae55487d4fe122739646f9280aasatok                    final int N = subtypesList.size();
3944e7c6998e0a953ae55487d4fe122739646f9280aasatok                    for (int i = 0; i < N; ++i) {
3945e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final InputMethodSubtype subtype = subtypesList.get(i);
3946e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.startTag(null, NODE_SUBTYPE);
3947e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.attribute(null, ATTR_ICON, String.valueOf(subtype.getIconResId()));
3948e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.attribute(null, ATTR_LABEL, String.valueOf(subtype.getNameResId()));
3949e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.attribute(null, ATTR_IME_SUBTYPE_LOCALE, subtype.getLocale());
3950e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.attribute(null, ATTR_IME_SUBTYPE_MODE, subtype.getMode());
3951e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.attribute(null, ATTR_IME_SUBTYPE_EXTRA_VALUE, subtype.getExtraValue());
3952e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.attribute(null, ATTR_IS_AUXILIARY,
3953e7c6998e0a953ae55487d4fe122739646f9280aasatok                                String.valueOf(subtype.isAuxiliary() ? 1 : 0));
3954e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.endTag(null, NODE_SUBTYPE);
3955e7c6998e0a953ae55487d4fe122739646f9280aasatok                    }
3956e7c6998e0a953ae55487d4fe122739646f9280aasatok                    out.endTag(null, NODE_IMI);
3957e7c6998e0a953ae55487d4fe122739646f9280aasatok                }
3958e7c6998e0a953ae55487d4fe122739646f9280aasatok                out.endTag(null, NODE_SUBTYPES);
3959e7c6998e0a953ae55487d4fe122739646f9280aasatok                out.endDocument();
3960e7c6998e0a953ae55487d4fe122739646f9280aasatok                subtypesFile.finishWrite(fos);
3961e7c6998e0a953ae55487d4fe122739646f9280aasatok            } catch (java.io.IOException e) {
3962e7c6998e0a953ae55487d4fe122739646f9280aasatok                Slog.w(TAG, "Error writing subtypes", e);
3963e7c6998e0a953ae55487d4fe122739646f9280aasatok                if (fos != null) {
3964e7c6998e0a953ae55487d4fe122739646f9280aasatok                    subtypesFile.failWrite(fos);
3965e7c6998e0a953ae55487d4fe122739646f9280aasatok                }
3966e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
3967e7c6998e0a953ae55487d4fe122739646f9280aasatok        }
3968e7c6998e0a953ae55487d4fe122739646f9280aasatok
3969e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static void readAdditionalInputMethodSubtypes(
3970e7c6998e0a953ae55487d4fe122739646f9280aasatok                HashMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile) {
3971e7c6998e0a953ae55487d4fe122739646f9280aasatok            if (allSubtypes == null || subtypesFile == null) return;
3972e7c6998e0a953ae55487d4fe122739646f9280aasatok            allSubtypes.clear();
3973e7c6998e0a953ae55487d4fe122739646f9280aasatok            FileInputStream fis = null;
3974e7c6998e0a953ae55487d4fe122739646f9280aasatok            try {
3975e7c6998e0a953ae55487d4fe122739646f9280aasatok                fis = subtypesFile.openRead();
3976e7c6998e0a953ae55487d4fe122739646f9280aasatok                final XmlPullParser parser = Xml.newPullParser();
3977e7c6998e0a953ae55487d4fe122739646f9280aasatok                parser.setInput(fis, null);
3978e7c6998e0a953ae55487d4fe122739646f9280aasatok                int type = parser.getEventType();
3979e7c6998e0a953ae55487d4fe122739646f9280aasatok                // Skip parsing until START_TAG
3980e7c6998e0a953ae55487d4fe122739646f9280aasatok                while ((type = parser.next()) != XmlPullParser.START_TAG
3981e7c6998e0a953ae55487d4fe122739646f9280aasatok                        && type != XmlPullParser.END_DOCUMENT) {}
3982e7c6998e0a953ae55487d4fe122739646f9280aasatok                String firstNodeName = parser.getName();
3983e7c6998e0a953ae55487d4fe122739646f9280aasatok                if (!NODE_SUBTYPES.equals(firstNodeName)) {
3984e7c6998e0a953ae55487d4fe122739646f9280aasatok                    throw new XmlPullParserException("Xml doesn't start with subtypes");
3985e7c6998e0a953ae55487d4fe122739646f9280aasatok                }
3986e7c6998e0a953ae55487d4fe122739646f9280aasatok                final int depth =parser.getDepth();
3987e7c6998e0a953ae55487d4fe122739646f9280aasatok                String currentImiId = null;
3988e7c6998e0a953ae55487d4fe122739646f9280aasatok                ArrayList<InputMethodSubtype> tempSubtypesArray = null;
3989e7c6998e0a953ae55487d4fe122739646f9280aasatok                while (((type = parser.next()) != XmlPullParser.END_TAG
3990e7c6998e0a953ae55487d4fe122739646f9280aasatok                        || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
3991e7c6998e0a953ae55487d4fe122739646f9280aasatok                    if (type != XmlPullParser.START_TAG)
3992e7c6998e0a953ae55487d4fe122739646f9280aasatok                        continue;
3993e7c6998e0a953ae55487d4fe122739646f9280aasatok                    final String nodeName = parser.getName();
3994e7c6998e0a953ae55487d4fe122739646f9280aasatok                    if (NODE_IMI.equals(nodeName)) {
3995e7c6998e0a953ae55487d4fe122739646f9280aasatok                        currentImiId = parser.getAttributeValue(null, ATTR_ID);
3996e7c6998e0a953ae55487d4fe122739646f9280aasatok                        if (TextUtils.isEmpty(currentImiId)) {
3997e7c6998e0a953ae55487d4fe122739646f9280aasatok                            Slog.w(TAG, "Invalid imi id found in subtypes.xml");
3998e7c6998e0a953ae55487d4fe122739646f9280aasatok                            continue;
3999e7c6998e0a953ae55487d4fe122739646f9280aasatok                        }
4000e7c6998e0a953ae55487d4fe122739646f9280aasatok                        tempSubtypesArray = new ArrayList<InputMethodSubtype>();
4001e7c6998e0a953ae55487d4fe122739646f9280aasatok                        allSubtypes.put(currentImiId, tempSubtypesArray);
4002e7c6998e0a953ae55487d4fe122739646f9280aasatok                    } else if (NODE_SUBTYPE.equals(nodeName)) {
4003e7c6998e0a953ae55487d4fe122739646f9280aasatok                        if (TextUtils.isEmpty(currentImiId) || tempSubtypesArray == null) {
4004e7c6998e0a953ae55487d4fe122739646f9280aasatok                            Slog.w(TAG, "IME uninstalled or not valid.: " + currentImiId);
4005e7c6998e0a953ae55487d4fe122739646f9280aasatok                            continue;
4006e7c6998e0a953ae55487d4fe122739646f9280aasatok                        }
4007e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final int icon = Integer.valueOf(
4008e7c6998e0a953ae55487d4fe122739646f9280aasatok                                parser.getAttributeValue(null, ATTR_ICON));
4009e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final int label = Integer.valueOf(
4010e7c6998e0a953ae55487d4fe122739646f9280aasatok                                parser.getAttributeValue(null, ATTR_LABEL));
4011e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final String imeSubtypeLocale =
4012e7c6998e0a953ae55487d4fe122739646f9280aasatok                                parser.getAttributeValue(null, ATTR_IME_SUBTYPE_LOCALE);
4013e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final String imeSubtypeMode =
4014e7c6998e0a953ae55487d4fe122739646f9280aasatok                                parser.getAttributeValue(null, ATTR_IME_SUBTYPE_MODE);
4015e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final String imeSubtypeExtraValue =
4016e7c6998e0a953ae55487d4fe122739646f9280aasatok                                parser.getAttributeValue(null, ATTR_IME_SUBTYPE_EXTRA_VALUE);
40174a28bde70e23b2ed151d52690da702da7f23cf5esatok                        final boolean isAuxiliary = "1".equals(String.valueOf(
40184a28bde70e23b2ed151d52690da702da7f23cf5esatok                                parser.getAttributeValue(null, ATTR_IS_AUXILIARY)));
4019e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final InputMethodSubtype subtype =
4020e7c6998e0a953ae55487d4fe122739646f9280aasatok                                new InputMethodSubtype(label, icon, imeSubtypeLocale,
4021e7c6998e0a953ae55487d4fe122739646f9280aasatok                                        imeSubtypeMode, imeSubtypeExtraValue, isAuxiliary);
4022e7c6998e0a953ae55487d4fe122739646f9280aasatok                        tempSubtypesArray.add(subtype);
4023e7c6998e0a953ae55487d4fe122739646f9280aasatok                    }
4024e7c6998e0a953ae55487d4fe122739646f9280aasatok                }
4025e7c6998e0a953ae55487d4fe122739646f9280aasatok            } catch (XmlPullParserException e) {
4026e7c6998e0a953ae55487d4fe122739646f9280aasatok                Slog.w(TAG, "Error reading subtypes: " + e);
4027e7c6998e0a953ae55487d4fe122739646f9280aasatok                return;
4028e7c6998e0a953ae55487d4fe122739646f9280aasatok            } catch (java.io.IOException e) {
4029e7c6998e0a953ae55487d4fe122739646f9280aasatok                Slog.w(TAG, "Error reading subtypes: " + e);
4030e7c6998e0a953ae55487d4fe122739646f9280aasatok                return;
4031e7c6998e0a953ae55487d4fe122739646f9280aasatok            } catch (NumberFormatException e) {
4032e7c6998e0a953ae55487d4fe122739646f9280aasatok                Slog.w(TAG, "Error reading subtypes: " + e);
4033e7c6998e0a953ae55487d4fe122739646f9280aasatok                return;
4034e7c6998e0a953ae55487d4fe122739646f9280aasatok            } finally {
4035e7c6998e0a953ae55487d4fe122739646f9280aasatok                if (fis != null) {
4036e7c6998e0a953ae55487d4fe122739646f9280aasatok                    try {
4037e7c6998e0a953ae55487d4fe122739646f9280aasatok                        fis.close();
4038e7c6998e0a953ae55487d4fe122739646f9280aasatok                    } catch (java.io.IOException e1) {
4039e7c6998e0a953ae55487d4fe122739646f9280aasatok                        Slog.w(TAG, "Failed to close.");
4040e7c6998e0a953ae55487d4fe122739646f9280aasatok                    }
4041e7c6998e0a953ae55487d4fe122739646f9280aasatok                }
4042e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
4043e7c6998e0a953ae55487d4fe122739646f9280aasatok        }
4044e7c6998e0a953ae55487d4fe122739646f9280aasatok    }
4045e7c6998e0a953ae55487d4fe122739646f9280aasatok
40469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ----------------------------------------------------------------------
40474e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    // Utilities for debug
40484e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    private static String getStackTrace() {
40494e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final StringBuilder sb = new StringBuilder();
40504e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        try {
40514e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            throw new RuntimeException();
40524e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        } catch (RuntimeException e) {
40534e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            final StackTraceElement[] frames = e.getStackTrace();
40544e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            // Start at 1 because the first frame is here and we don't care about it
40554e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            for (int j = 1; j < frames.length; ++j) {
40564e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                sb.append(frames[j].toString() + "\n");
40574e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
40584e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
40594e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        return sb.toString();
40604e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    }
4061ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
40629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
40639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
40649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
40659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                != PackageManager.PERMISSION_GRANTED) {
4066ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
40679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println("Permission Denial: can't dump InputMethodManager from from pid="
40689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + Binder.getCallingPid()
40699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + ", uid=" + Binder.getCallingUid());
40709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
40719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
40729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
40739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IInputMethod method;
40749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ClientState client;
4075ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
40769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Printer p = new PrintWriterPrinter(pw);
4077ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
40789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
40799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("Current Input Method Manager state:");
40809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int N = mMethodList.size();
40819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  Input Methods:");
40829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i=0; i<N; i++) {
40839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                InputMethodInfo info = mMethodList.get(i);
40849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("  InputMethod #" + i + ":");
40859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                info.dump(p, "    ");
40869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
40879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  Clients:");
40889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (ClientState ci : mClients.values()) {
40899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("  Client " + ci + ":");
40909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("    client=" + ci.client);
40919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("    inputContext=" + ci.inputContext);
40929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("    sessionRequested=" + ci.sessionRequested);
40939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("    curSession=" + ci.curSession);
40949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4095105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            p.println("  mCurMethodId=" + mCurMethodId);
40969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            client = mCurClient;
4097b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            p.println("  mCurClient=" + client + " mCurSeq=" + mCurSeq);
4098b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            p.println("  mCurFocusedWindow=" + mCurFocusedWindow);
40999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mCurId=" + mCurId + " mHaveConnect=" + mHaveConnection
41009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mBoundToMethod=" + mBoundToMethod);
41019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mCurToken=" + mCurToken);
41029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mCurIntent=" + mCurIntent);
41039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            method = mCurMethod;
41049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mCurMethod=" + mCurMethod);
41059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mEnabledSession=" + mEnabledSession);
41069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mShowRequested=" + mShowRequested
41079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
41089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mShowForced=" + mShowForced
41099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mInputShown=" + mInputShown);
4110cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn            p.println("  mSystemReady=" + mSystemReady + " mScreenOn=" + mScreenOn);
41119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4112ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
4113b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown        p.println(" ");
41149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (client != null) {
41159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.flush();
41169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
41179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                client.client.asBinder().dump(fd, args);
41189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
41199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("Input method client dead: " + e);
41209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4121b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown        } else {
4122b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown            p.println("No input method client.");
41239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4124ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
4125b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown        p.println(" ");
41269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (method != null) {
41279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.flush();
41289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
41299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                method.asBinder().dump(fd, args);
41309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
41319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("Input method service dead: " + e);
41329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4133b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown        } else {
4134b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown            p.println("No input method service.");
41359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
41369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
41379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4138