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;
389bc7b6fc2a4b701596a2c8eecc4aeef522abeeafaJohn Spurlock    private boolean mInputBoundToKeyguard;
390ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class SettingsObserver extends ContentObserver {
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SettingsObserver(Handler handler) {
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(handler);
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ContentResolver resolver = mContext.getContentResolver();
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            resolver.registerContentObserver(Settings.Secure.getUriFor(
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
397ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            resolver.registerContentObserver(Settings.Secure.getUriFor(
398b6109bb591bc02bf8a2d9d5ca76d69d1961c9b5fsatok                    Settings.Secure.ENABLED_INPUT_METHODS), false, this);
399b6109bb591bc02bf8a2d9d5ca76d69d1961c9b5fsatok            resolver.registerContentObserver(Settings.Secure.getUriFor(
400ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this);
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
402ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override public void onChange(boolean selfChange) {
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                updateFromSettingsLocked();
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
409ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
4104e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    class ImmsBroadcastReceiver extends android.content.BroadcastReceiver {
4114e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        private void updateActive() {
4124e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            // Inform the current client of the change in active status
4134e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (mCurClient != null && mCurClient.client != null) {
4144e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
4154e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        MSG_SET_ACTIVE, mScreenOn ? 1 : 0, mCurClient));
4164e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
4174e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
4184e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
4214e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            final String action = intent.getAction();
4224e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (Intent.ACTION_SCREEN_ON.equals(action)) {
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mScreenOn = true;
4243afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok                refreshImeWindowVisibilityLocked();
4254e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                updateActive();
4264e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                return;
4274e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mScreenOn = false;
42915452a487a4c0274f4217cd060aa54446f30a8f3satok                setImeWindowVisibilityStatusHiddenLocked();
4304e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                updateActive();
4314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                return;
4324e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            } else if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
433105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                hideInputMethodMenu();
4344e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                // No need to updateActive
435105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                return;
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
4378a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Unexpected intent " + intent);
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
441ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
44221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    class MyPackageMonitor extends PackageMonitor {
4434e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        private boolean isChangingPackagesOfCurrentUser() {
4444e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            final int userId = getChangingUserId();
4454e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            final boolean retval = userId == mSettings.getCurrentUserId();
4464e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
44781f8b7c66750a0a89c8e6b6037136ca169c96f95satok                if (!retval) {
44881f8b7c66750a0a89c8e6b6037136ca169c96f95satok                    Slog.d(TAG, "--- ignore this call back from a background user: " + userId);
44981f8b7c66750a0a89c8e6b6037136ca169c96f95satok                }
4504e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
4514e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return retval;
4524e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
4534e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
45521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
4564e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (!isChangingPackagesOfCurrentUser()) {
4574e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                return false;
4584e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
45921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            synchronized (mMethodMap) {
4604e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                String curInputMethodId = mSettings.getSelectedInputMethod();
46121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                final int N = mMethodList.size();
46221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                if (curInputMethodId != null) {
46321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    for (int i=0; i<N; i++) {
46421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        InputMethodInfo imi = mMethodList.get(i);
46521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        if (imi.getId().equals(curInputMethodId)) {
46621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            for (String pkg : packages) {
46721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                if (imi.getPackageName().equals(pkg)) {
46821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    if (!doit) {
46921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                        return true;
47021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    }
471723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                                    resetSelectedInputMethodAndSubtypeLocked("");
47221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    chooseNewDefaultIMELocked();
47321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    return true;
47421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                }
47521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            }
47621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        }
47721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    }
47808675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                }
47908675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu            }
48021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            return false;
48121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        }
482ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
48321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        @Override
48421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        public void onSomePackagesChanged() {
4854e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (!isChangingPackagesOfCurrentUser()) {
4864e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                return;
4874e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
48821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            synchronized (mMethodMap) {
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                InputMethodInfo curIm = null;
4904e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                String curInputMethodId = mSettings.getSelectedInputMethod();
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int N = mMethodList.size();
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (curInputMethodId != null) {
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (int i=0; i<N; i++) {
49421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        InputMethodInfo imi = mMethodList.get(i);
495e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final String imiId = imi.getId();
496e7c6998e0a953ae55487d4fe122739646f9280aasatok                        if (imiId.equals(curInputMethodId)) {
49721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            curIm = imi;
49821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        }
499e7c6998e0a953ae55487d4fe122739646f9280aasatok
50021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        int change = isPackageDisappearing(imi.getPackageName());
501e7c6998e0a953ae55487d4fe122739646f9280aasatok                        if (isPackageModified(imi.getPackageName())) {
502e7c6998e0a953ae55487d4fe122739646f9280aasatok                            mFileManager.deleteAllInputMethodSubtypes(imiId);
503e7c6998e0a953ae55487d4fe122739646f9280aasatok                        }
50421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                        if (change == PACKAGE_TEMPORARY_CHANGE
50521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                || change == PACKAGE_PERMANENT_CHANGE) {
5068a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            Slog.i(TAG, "Input method uninstalled, disabling: "
50721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                                    + imi.getComponent());
50821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            setInputMethodEnabledLocked(imi.getId(), false);
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
512ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
51321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                buildInputMethodListLocked(mMethodList, mMethodMap);
51421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean changed = false;
516ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
51708675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                if (curIm != null) {
51821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    int change = isPackageDisappearing(curIm.getPackageName());
51921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    if (change == PACKAGE_TEMPORARY_CHANGE
52021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            || change == PACKAGE_PERMANENT_CHANGE) {
52108675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        ServiceInfo si = null;
52208675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        try {
5234e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                            si = mIPackageManager.getServiceInfo(
5244e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                    curIm.getComponent(), 0, mSettings.getCurrentUserId());
5254e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        } catch (RemoteException ex) {
52608675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        }
52708675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        if (si == null) {
52808675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                            // Uh oh, current input method is no longer around!
52908675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                            // Pick another one...
5308a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            Slog.i(TAG, "Current input method removed: " + curInputMethodId);
53115452a487a4c0274f4217cd060aa54446f30a8f3satok                            setImeWindowVisibilityStatusHiddenLocked();
53221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                            if (!chooseNewDefaultIMELocked()) {
53308675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                                changed = true;
53408675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                                curIm = null;
5358a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                                Slog.i(TAG, "Unsetting current input method");
536723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                                resetSelectedInputMethodAndSubtypeLocked("");
53708675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                            }
53808675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                        }
53908675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu                    }
54021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                }
541ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
54221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                if (curIm == null) {
54321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    // We currently don't have a default input method... is
54421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    // one now available?
54521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    changed = chooseNewDefaultIMELocked();
54621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                }
547ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
54821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                if (changed) {
54921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                    updateFromSettingsLocked();
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
554ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
555e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard    private static class MethodCallback extends IInputMethodCallback.Stub {
556e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard        private final IInputMethod mMethod;
557e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard        private final InputMethodManagerService mParentIMMS;
558ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
559e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard        MethodCallback(final IInputMethod method, final InputMethodManagerService imms) {
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMethod = method;
561e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard            mParentIMMS = imms;
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
563ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
564e7c6998e0a953ae55487d4fe122739646f9280aasatok        @Override
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void finishedEvent(int seq, boolean handled) throws RemoteException {
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
568e7c6998e0a953ae55487d4fe122739646f9280aasatok        @Override
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void sessionCreated(IInputMethodSession session) throws RemoteException {
570e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard            mParentIMMS.onSessionCreated(mMethod, session);
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
573ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
57401038492ff0317f0d3cff54d8a7ee36bb31ff175satok    private class HardKeyboardListener
57501038492ff0317f0d3cff54d8a7ee36bb31ff175satok            implements WindowManagerService.OnHardKeyboardStatusChangeListener {
57601038492ff0317f0d3cff54d8a7ee36bb31ff175satok        @Override
57701038492ff0317f0d3cff54d8a7ee36bb31ff175satok        public void onHardKeyboardStatusChange(boolean available, boolean enabled) {
57801038492ff0317f0d3cff54d8a7ee36bb31ff175satok            mHandler.sendMessage(mHandler.obtainMessage(
57901038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    MSG_HARD_KEYBOARD_SWITCH_CHANGED, available ? 1 : 0, enabled ? 1 : 0));
58001038492ff0317f0d3cff54d8a7ee36bb31ff175satok        }
58101038492ff0317f0d3cff54d8a7ee36bb31ff175satok
58201038492ff0317f0d3cff54d8a7ee36bb31ff175satok        public void handleHardKeyboardStatusChange(boolean available, boolean enabled) {
58301038492ff0317f0d3cff54d8a7ee36bb31ff175satok            if (DEBUG) {
58401038492ff0317f0d3cff54d8a7ee36bb31ff175satok                Slog.w(TAG, "HardKeyboardStatusChanged: available = " + available + ", enabled = "
58501038492ff0317f0d3cff54d8a7ee36bb31ff175satok                        + enabled);
58601038492ff0317f0d3cff54d8a7ee36bb31ff175satok            }
58701038492ff0317f0d3cff54d8a7ee36bb31ff175satok            synchronized(mMethodMap) {
58801038492ff0317f0d3cff54d8a7ee36bb31ff175satok                if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
58901038492ff0317f0d3cff54d8a7ee36bb31ff175satok                        && mSwitchingDialog.isShowing()) {
59001038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    mSwitchingDialogTitleView.findViewById(
59101038492ff0317f0d3cff54d8a7ee36bb31ff175satok                            com.android.internal.R.id.hard_keyboard_section).setVisibility(
59201038492ff0317f0d3cff54d8a7ee36bb31ff175satok                                    available ? View.VISIBLE : View.GONE);
59301038492ff0317f0d3cff54d8a7ee36bb31ff175satok                }
59401038492ff0317f0d3cff54d8a7ee36bb31ff175satok            }
59501038492ff0317f0d3cff54d8a7ee36bb31ff175satok        }
59601038492ff0317f0d3cff54d8a7ee36bb31ff175satok    }
59701038492ff0317f0d3cff54d8a7ee36bb31ff175satok
59801038492ff0317f0d3cff54d8a7ee36bb31ff175satok    public InputMethodManagerService(Context context, WindowManagerService windowManager) {
5994e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        mIPackageManager = AppGlobals.getPackageManager();
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
6017d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn        mRes = context.getResources();
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler = new Handler(this);
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIWindowManager = IWindowManager.Stub.asInterface(
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ServiceManager.getService(Context.WINDOW_SERVICE));
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCaller = new HandlerCaller(context, new HandlerCaller.Callback() {
606e7c6998e0a953ae55487d4fe122739646f9280aasatok            @Override
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void executeMessage(Message msg) {
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handleMessage(msg);
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        });
61101038492ff0317f0d3cff54d8a7ee36bb31ff175satok        mWindowManagerService = windowManager;
61201038492ff0317f0d3cff54d8a7ee36bb31ff175satok        mHardKeyboardListener = new HardKeyboardListener();
6137cfc0ed21a3fafabafb40b38a8589808ad1517afsatok
6147cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification = new Notification();
6157cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification.icon = com.android.internal.R.drawable.ic_notification_ime_default;
6167cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification.when = 0;
6177cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification.flags = Notification.FLAG_ONGOING_EVENT;
6187cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification.tickerText = null;
6197cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification.defaults = 0; // please be quiet
6207cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification.sound = null;
6217cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mImeSwitcherNotification.vibrate = null;
622590d515d912396a0c293d78529ac0dbc224400bfDaniel Sandler
623590d515d912396a0c293d78529ac0dbc224400bfDaniel Sandler        // Tag this notification specially so SystemUI knows it's important
624590d515d912396a0c293d78529ac0dbc224400bfDaniel Sandler        mImeSwitcherNotification.kind = new String[] { "android.system.imeswitcher" };
625590d515d912396a0c293d78529ac0dbc224400bfDaniel Sandler
6267cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
627683e2383c8549f95e00bade15daed3dbddf13950satok        mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
628b858c732f665fe9610f2d913230ae625f44a8caasatok
629b858c732f665fe9610f2d913230ae625f44a8caasatok        mShowOngoingImeSwitcherForPhones = false;
6307cfc0ed21a3fafabafb40b38a8589808ad1517afsatok
6314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final IntentFilter broadcastFilter = new IntentFilter();
6324e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        broadcastFilter.addAction(Intent.ACTION_SCREEN_ON);
6334e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        broadcastFilter.addAction(Intent.ACTION_SCREEN_OFF);
6344e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        broadcastFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
6354e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        mContext.registerReceiver(new ImmsBroadcastReceiver(), broadcastFilter);
636ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
6377cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        mNotificationShown = false;
6384e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        int userId = 0;
6394e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        try {
6404e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            ActivityManagerNative.getDefault().registerUserSwitchObserver(
6414e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    new IUserSwitchObserver.Stub() {
6424e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        @Override
6434e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        public void onUserSwitching(int newUserId, IRemoteCallback reply) {
6445ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka                            synchronized(mMethodMap) {
6455ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka                                switchUserLocked(newUserId);
6465ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka                            }
6474e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                            if (reply != null) {
6484e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                try {
6494e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                    reply.sendResult(null);
6504e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                } catch (RemoteException e) {
6514e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                }
6524e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                            }
6534e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        }
6544e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
6554e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        @Override
6564e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        public void onUserSwitchComplete(int newUserId) throws RemoteException {
6574e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        }
6584e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    });
6594e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            userId = ActivityManagerNative.getDefault().getCurrentUser().id;
6604e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        } catch (RemoteException e) {
6614e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
6624e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
66381f8b7c66750a0a89c8e6b6037136ca169c96f95satok        mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
664913a8925c07e854a80bf5df87561f290d3a56d61satok
665d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // mSettings should be created before buildInputMethodListLocked
666df31ae6a3011d47421a6ac10021f9649dc34a156satok        mSettings = new InputMethodSettings(
6674e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                mRes, context.getContentResolver(), mMethodMap, mMethodList, userId);
6685ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka        mFileManager = new InputMethodFileManager(mMethodMap, userId);
6695ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka        mImListManager = new InputMethodAndSubtypeListManager(context, this);
6700a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok
6710a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok        // Just checking if defaultImiId is empty or not
6724e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final String defaultImiId = mSettings.getSelectedInputMethod();
6730a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok        mImeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
6740a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        buildInputMethodListLocked(mMethodList, mMethodMap);
676d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        mSettings.enableAllIMEsIfThereIsNoEnabledIME();
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6780a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok        if (!mImeSelectedOnBoot) {
6790a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            Slog.w(TAG, "No IME selected. Choose the most applicable IME.");
6805b927c431f54ea47c3333afb7940d79e2e863f1asatok            resetDefaultImeLocked(context);
6815b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
6825b927c431f54ea47c3333afb7940d79e2e863f1asatok
6835b927c431f54ea47c3333afb7940d79e2e863f1asatok        mSettingsObserver = new SettingsObserver(mHandler);
6845b927c431f54ea47c3333afb7940d79e2e863f1asatok        updateFromSettingsLocked();
6855b927c431f54ea47c3333afb7940d79e2e863f1asatok
6865b927c431f54ea47c3333afb7940d79e2e863f1asatok        // IMMS wants to receive Intent.ACTION_LOCALE_CHANGED in order to update the current IME
6875b927c431f54ea47c3333afb7940d79e2e863f1asatok        // according to the new system locale.
6885b927c431f54ea47c3333afb7940d79e2e863f1asatok        final IntentFilter filter = new IntentFilter();
6895b927c431f54ea47c3333afb7940d79e2e863f1asatok        filter.addAction(Intent.ACTION_LOCALE_CHANGED);
6905b927c431f54ea47c3333afb7940d79e2e863f1asatok        mContext.registerReceiver(
6915b927c431f54ea47c3333afb7940d79e2e863f1asatok                new BroadcastReceiver() {
6925b927c431f54ea47c3333afb7940d79e2e863f1asatok                    @Override
6935b927c431f54ea47c3333afb7940d79e2e863f1asatok                    public void onReceive(Context context, Intent intent) {
6945b927c431f54ea47c3333afb7940d79e2e863f1asatok                        synchronized(mMethodMap) {
6955b927c431f54ea47c3333afb7940d79e2e863f1asatok                            checkCurrentLocaleChangedLocked();
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
6985b927c431f54ea47c3333afb7940d79e2e863f1asatok                }, filter);
6995b927c431f54ea47c3333afb7940d79e2e863f1asatok    }
7005b927c431f54ea47c3333afb7940d79e2e863f1asatok
7015b927c431f54ea47c3333afb7940d79e2e863f1asatok    private void resetDefaultImeLocked(Context context) {
7025b927c431f54ea47c3333afb7940d79e2e863f1asatok        // Do not reset the default (current) IME when it is a 3rd-party IME
7035b927c431f54ea47c3333afb7940d79e2e863f1asatok        if (mCurMethodId != null && !isSystemIme(mMethodMap.get(mCurMethodId))) {
7045b927c431f54ea47c3333afb7940d79e2e863f1asatok            return;
7055b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
7065b927c431f54ea47c3333afb7940d79e2e863f1asatok
7075b927c431f54ea47c3333afb7940d79e2e863f1asatok        InputMethodInfo defIm = null;
7085b927c431f54ea47c3333afb7940d79e2e863f1asatok        for (InputMethodInfo imi : mMethodList) {
7095b927c431f54ea47c3333afb7940d79e2e863f1asatok            if (defIm == null) {
7105b927c431f54ea47c3333afb7940d79e2e863f1asatok                if (isValidSystemDefaultIme(imi, context)) {
7115b927c431f54ea47c3333afb7940d79e2e863f1asatok                    defIm = imi;
7125b927c431f54ea47c3333afb7940d79e2e863f1asatok                    Slog.i(TAG, "Selected default: " + imi.getId());
7135b927c431f54ea47c3333afb7940d79e2e863f1asatok                }
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7155b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
7165b927c431f54ea47c3333afb7940d79e2e863f1asatok        if (defIm == null && mMethodList.size() > 0) {
7175b927c431f54ea47c3333afb7940d79e2e863f1asatok            defIm = getMostApplicableDefaultIMELocked();
7185b927c431f54ea47c3333afb7940d79e2e863f1asatok            Slog.i(TAG, "No default found, using " + defIm.getId());
7195b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
7205b927c431f54ea47c3333afb7940d79e2e863f1asatok        if (defIm != null) {
7215b927c431f54ea47c3333afb7940d79e2e863f1asatok            setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
7225b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
7235b927c431f54ea47c3333afb7940d79e2e863f1asatok    }
7245b927c431f54ea47c3333afb7940d79e2e863f1asatok
7254e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    private void resetAllInternalStateLocked(boolean updateOnlyWhenLocaleChanged) {
7264e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!mSystemReady) {
7274e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            // not system ready
7284e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
7294e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
7304e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final Locale newLocale = mRes.getConfiguration().locale;
7314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!updateOnlyWhenLocaleChanged
7324e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                || (newLocale != null && !newLocale.equals(mLastSystemLocale))) {
7334e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (!updateOnlyWhenLocaleChanged) {
7344e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                hideCurrentInputLocked(0, null);
7354e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                mCurMethodId = null;
7362ea9bae7121f1df5461437d7d08fa550cdf6e0b0Dianne Hackborn                unbindCurrentMethodLocked(true, false);
7374e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
7384e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
7394e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.i(TAG, "Locale has been changed to " + newLocale);
7404e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
7415ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka            // InputMethodAndSubtypeListManager should be reset when the locale is changed.
7425ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka            mImListManager = new InputMethodAndSubtypeListManager(mContext, this);
7434e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            buildInputMethodListLocked(mMethodList, mMethodMap);
7444e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (!updateOnlyWhenLocaleChanged) {
7454e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                final String selectedImiId = mSettings.getSelectedInputMethod();
7464e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                if (TextUtils.isEmpty(selectedImiId)) {
7474e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    // This is the first time of the user switch and
7484e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    // set the current ime to the proper one.
7494e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    resetDefaultImeLocked(mContext);
7504e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                }
751d08a9238db0de62c956788ceebb227d099ad88c2Satoshi Kataoka            } else {
752d08a9238db0de62c956788ceebb227d099ad88c2Satoshi Kataoka                // If the locale is changed, needs to reset the default ime
753d08a9238db0de62c956788ceebb227d099ad88c2Satoshi Kataoka                resetDefaultImeLocked(mContext);
7544e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
7554e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            updateFromSettingsLocked();
7564e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            mLastSystemLocale = newLocale;
7574e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (!updateOnlyWhenLocaleChanged) {
7584e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                try {
7594e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    startInputInnerLocked();
7604e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                } catch (RuntimeException e) {
7614e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    Slog.w(TAG, "Unexpected exception", e);
7624e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                }
7634e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
7644e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
7654e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    }
7664e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
7674e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    private void checkCurrentLocaleChangedLocked() {
7684e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        resetAllInternalStateLocked(true);
7694e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    }
7704e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
7715ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka    private void switchUserLocked(int newUserId) {
7724e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        mSettings.setCurrentUserId(newUserId);
7735ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka        // InputMethodFileManager should be reset when the user is changed
7745ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka        mFileManager = new InputMethodFileManager(mMethodMap, newUserId);
7754e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        resetAllInternalStateLocked(false);
7764e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    }
7774e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
7780a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok    private boolean isValidSystemDefaultIme(InputMethodInfo imi, Context context) {
7790a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok        if (!mSystemReady) {
7800a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            return false;
7810a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok        }
7825b927c431f54ea47c3333afb7940d79e2e863f1asatok        if (!isSystemIme(imi)) {
7835b927c431f54ea47c3333afb7940d79e2e863f1asatok            return false;
7845b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
7855b927c431f54ea47c3333afb7940d79e2e863f1asatok        if (imi.getIsDefaultResourceId() != 0) {
7865b927c431f54ea47c3333afb7940d79e2e863f1asatok            try {
7875b927c431f54ea47c3333afb7940d79e2e863f1asatok                Resources res = context.createPackageContext(
7885b927c431f54ea47c3333afb7940d79e2e863f1asatok                        imi.getPackageName(), 0).getResources();
7895b927c431f54ea47c3333afb7940d79e2e863f1asatok                if (res.getBoolean(imi.getIsDefaultResourceId())
7905b927c431f54ea47c3333afb7940d79e2e863f1asatok                        && containsSubtypeOf(imi, context.getResources().getConfiguration().
7915b927c431f54ea47c3333afb7940d79e2e863f1asatok                                locale.getLanguage())) {
7925b927c431f54ea47c3333afb7940d79e2e863f1asatok                    return true;
7935b927c431f54ea47c3333afb7940d79e2e863f1asatok                }
7945b927c431f54ea47c3333afb7940d79e2e863f1asatok            } catch (PackageManager.NameNotFoundException ex) {
7955b927c431f54ea47c3333afb7940d79e2e863f1asatok            } catch (Resources.NotFoundException ex) {
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7985b927c431f54ea47c3333afb7940d79e2e863f1asatok        if (imi.getSubtypeCount() == 0) {
7995b927c431f54ea47c3333afb7940d79e2e863f1asatok            Slog.w(TAG, "Found no subtypes in a system IME: " + imi.getPackageName());
8005b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
8015b927c431f54ea47c3333afb7940d79e2e863f1asatok        return false;
8025b927c431f54ea47c3333afb7940d79e2e863f1asatok    }
803ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
8045b927c431f54ea47c3333afb7940d79e2e863f1asatok    private static boolean isSystemImeThatHasEnglishSubtype(InputMethodInfo imi) {
8055b927c431f54ea47c3333afb7940d79e2e863f1asatok        if (!isSystemIme(imi)) {
8065b927c431f54ea47c3333afb7940d79e2e863f1asatok            return false;
8075b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
8085b927c431f54ea47c3333afb7940d79e2e863f1asatok        return containsSubtypeOf(imi, ENGLISH_LOCALE.getLanguage());
8095b927c431f54ea47c3333afb7940d79e2e863f1asatok    }
8105b927c431f54ea47c3333afb7940d79e2e863f1asatok
8115b927c431f54ea47c3333afb7940d79e2e863f1asatok    private static boolean containsSubtypeOf(InputMethodInfo imi, String language) {
8125b927c431f54ea47c3333afb7940d79e2e863f1asatok        final int N = imi.getSubtypeCount();
8135b927c431f54ea47c3333afb7940d79e2e863f1asatok        for (int i = 0; i < N; ++i) {
8145b927c431f54ea47c3333afb7940d79e2e863f1asatok            if (imi.getSubtypeAt(i).getLocale().startsWith(language)) {
8155b927c431f54ea47c3333afb7940d79e2e863f1asatok                return true;
8165b927c431f54ea47c3333afb7940d79e2e863f1asatok            }
8175b927c431f54ea47c3333afb7940d79e2e863f1asatok        }
8185b927c431f54ea47c3333afb7940d79e2e863f1asatok        return false;
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws RemoteException {
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return super.onTransact(code, data, reply, flags);
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (RuntimeException e) {
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // The input method manager only throws security exceptions, so let's
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // log all others.
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!(e instanceof SecurityException)) {
8308a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.e(TAG, "Input Method Manager Crash", e);
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw e;
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
836661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn    public void systemReady(StatusBarManagerService statusBar) {
837a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        synchronized (mMethodMap) {
8384e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
8394e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "--- systemReady");
8404e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
841a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            if (!mSystemReady) {
842a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn                mSystemReady = true;
8434e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                mKeyguardManager =
8444e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
845661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                mNotificationManager = (NotificationManager)
846661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
847661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                mStatusBar = statusBar;
848661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                statusBar.setIconVisibility("ime", false);
849661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                updateImeWindowStatusLocked();
850b858c732f665fe9610f2d913230ae625f44a8caasatok                mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
851b858c732f665fe9610f2d913230ae625f44a8caasatok                        com.android.internal.R.bool.show_ongoing_ime_switcher);
85201038492ff0317f0d3cff54d8a7ee36bb31ff175satok                if (mShowOngoingImeSwitcherForPhones) {
85301038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    mWindowManagerService.setOnHardKeyboardStatusChangeListener(
85401038492ff0317f0d3cff54d8a7ee36bb31ff175satok                            mHardKeyboardListener);
85501038492ff0317f0d3cff54d8a7ee36bb31ff175satok                }
8560a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                buildInputMethodListLocked(mMethodList, mMethodMap);
8570a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                if (!mImeSelectedOnBoot) {
8580a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                    Slog.w(TAG, "Reset the default IME as \"Resource\" is ready here.");
8590a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                    checkCurrentLocaleChangedLocked();
8600a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                }
8610a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                mLastSystemLocale = mRes.getConfiguration().locale;
862cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                try {
863cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                    startInputInnerLocked();
864cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                } catch (RuntimeException e) {
8658a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.w(TAG, "Unexpected exception", e);
866cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                }
867a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            }
868a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        }
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
870ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
87115452a487a4c0274f4217cd060aa54446f30a8f3satok    private void setImeWindowVisibilityStatusHiddenLocked() {
87215452a487a4c0274f4217cd060aa54446f30a8f3satok        mImeWindowVis = 0;
87315452a487a4c0274f4217cd060aa54446f30a8f3satok        updateImeWindowStatusLocked();
87415452a487a4c0274f4217cd060aa54446f30a8f3satok    }
87515452a487a4c0274f4217cd060aa54446f30a8f3satok
8763afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok    private void refreshImeWindowVisibilityLocked() {
8773afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok        final Configuration conf = mRes.getConfiguration();
8783afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok        final boolean haveHardKeyboard = conf.keyboard
8793afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok                != Configuration.KEYBOARD_NOKEYS;
8803afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok        final boolean hardKeyShown = haveHardKeyboard
8813afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok                && conf.hardKeyboardHidden
8823afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok                        != Configuration.HARDKEYBOARDHIDDEN_YES;
883bc7b6fc2a4b701596a2c8eecc4aeef522abeeafaJohn Spurlock        final boolean isScreenLocked =
884bc7b6fc2a4b701596a2c8eecc4aeef522abeeafaJohn Spurlock                mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
885bc7b6fc2a4b701596a2c8eecc4aeef522abeeafaJohn Spurlock        final boolean isScreenSecurelyLocked =
886bc7b6fc2a4b701596a2c8eecc4aeef522abeeafaJohn Spurlock                isScreenLocked && mKeyguardManager.isKeyguardSecure();
887bc7b6fc2a4b701596a2c8eecc4aeef522abeeafaJohn Spurlock        final boolean inputShown = mInputShown && (!isScreenLocked || mInputBoundToKeyguard);
888bc7b6fc2a4b701596a2c8eecc4aeef522abeeafaJohn Spurlock        mImeWindowVis = (!isScreenSecurelyLocked && (inputShown || hardKeyShown)) ?
8893afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok                (InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE) : 0;
8903afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok        updateImeWindowStatusLocked();
8913afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok    }
8923afd6c0d4d5c2c80cf0450941babaee32ec9c7eesatok
89315452a487a4c0274f4217cd060aa54446f30a8f3satok    private void updateImeWindowStatusLocked() {
894dbf2950781ab0c4c0fc4ad9bd71b13c55ae6f471satok        setImeWindowStatus(mCurToken, mImeWindowVis, mBackDisposition);
895661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn    }
896661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn
8974e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    // ---------------------------------------------------------------------------------------
8984e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    // Check whether or not this is a valid IPC. Assumes an IPC is valid when either
8994e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    // 1) it comes from the system process
9004e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    // 2) the calling process' user id is identical to the current user id IMMS thinks.
9014e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    private boolean calledFromValidUser() {
9024e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final int uid = Binder.getCallingUid();
9034e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final int userId = UserHandle.getUserId(uid);
9044e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (DEBUG) {
9054e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
9064e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
9074e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    + " calling userId = " + userId + ", foreground user id = "
908c86884cd839123e3be3cc97c8f293ac47d3624a9Satoshi Kataoka                    + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid());
9094e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
9104e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (uid == Process.SYSTEM_UID || userId == mSettings.getCurrentUserId()) {
9114e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return true;
9124e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
913135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka
914135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        // Caveat: A process which has INTERACT_ACROSS_USERS_FULL gets results for the
915135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        // foreground user, not for the user of that process. Accordingly InputMethodManagerService
916135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        // must not manage background users' states in any functions.
917135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        // Note that privacy-sensitive IPCs, such as setInputMethod, are still securely guarded
918135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        // by a token.
919135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        if (mContext.checkCallingOrSelfPermission(
920135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
921135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        == PackageManager.PERMISSION_GRANTED) {
922135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka            if (DEBUG) {
923135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                Slog.d(TAG, "--- Access granted because the calling process has "
924135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        + "the INTERACT_ACROSS_USERS_FULL permission");
925135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka            }
926135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka            return true;
927135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        }
928135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        Slog.w(TAG, "--- IPC called from background users. Ignore. \n" + getStackTrace());
929135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka        return false;
9304e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    }
9314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
9324e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    private boolean bindCurrentInputMethodService(
9334e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Intent service, ServiceConnection conn, int flags) {
9344e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (service == null || conn == null) {
9354e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn);
9364e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
9374e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
9384e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        return mContext.bindService(service, conn, flags, mSettings.getCurrentUserId());
9394e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    }
9404e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
941e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public List<InputMethodInfo> getInputMethodList() {
9434e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // TODO: Make this work even for non-current users?
9444e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
9454e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return Collections.emptyList();
9464e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new ArrayList<InputMethodInfo>(mMethodList);
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
952e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public List<InputMethodInfo> getEnabledInputMethodList() {
9544e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // TODO: Make this work even for non-current users?
9554e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
9564e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return Collections.emptyList();
9574e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
959d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return mSettings.getEnabledInputMethodListLocked();
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
963bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok    private HashMap<InputMethodInfo, List<InputMethodSubtype>>
964bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            getExplicitlyOrImplicitlyEnabledInputMethodsAndSubtypeListLocked() {
965bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        HashMap<InputMethodInfo, List<InputMethodSubtype>> enabledInputMethodAndSubtypes =
966bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                new HashMap<InputMethodInfo, List<InputMethodSubtype>>();
9674e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        for (InputMethodInfo imi: mSettings.getEnabledInputMethodListLocked()) {
968bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            enabledInputMethodAndSubtypes.put(
969bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                    imi, getEnabledInputMethodSubtypeListLocked(imi, true));
970bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        }
971bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        return enabledInputMethodAndSubtypes;
972bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok    }
973bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok
974bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok    public List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(InputMethodInfo imi,
975bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            boolean allowsImplicitlySelectedSubtypes) {
976bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        if (imi == null && mCurMethodId != null) {
977bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            imi = mMethodMap.get(mCurMethodId);
978bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        }
9797265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        List<InputMethodSubtype> enabledSubtypes =
980bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                mSettings.getEnabledInputMethodSubtypeListLocked(imi);
9817265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        if (allowsImplicitlySelectedSubtypes && enabledSubtypes.isEmpty()) {
982a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            enabledSubtypes = getImplicitlyApplicableSubtypesLocked(mRes, imi);
983bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        }
9847265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        return InputMethodSubtype.sort(mContext, 0, imi, enabledSubtypes);
985bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok    }
986bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok
987e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
98816331c8a1d33defccc5cbb18694def79196c921bsatok    public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
98916331c8a1d33defccc5cbb18694def79196c921bsatok            boolean allowsImplicitlySelectedSubtypes) {
9904e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // TODO: Make this work even for non-current users?
9914e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
9924e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return Collections.emptyList();
9934e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
99467ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok        synchronized (mMethodMap) {
995bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            return getEnabledInputMethodSubtypeListLocked(imi, allowsImplicitlySelectedSubtypes);
99667ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok        }
99767ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok    }
99867ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok
999e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addClient(IInputMethodClient client,
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            IInputContext inputContext, int uid, int pid) {
10024e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
10034e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
10044e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClients.put(client.asBinder(), new ClientState(client,
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    inputContext, uid, pid));
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1010ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1011e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void removeClient(IInputMethodClient client) {
10134e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
10144e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
10154e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClients.remove(client.asBinder());
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1020ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void executeOrSendMessage(IInterface target, Message msg) {
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         if (target.asBinder() instanceof Binder) {
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             mCaller.sendMessage(msg);
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         } else {
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             handleMessage(msg);
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             msg.recycle();
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         }
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1029ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1030b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    void unbindCurrentClientLocked() {
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurClient != null) {
10328a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client = "
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + mCurClient.client.asBinder());
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mBoundToMethod) {
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBoundToMethod = false;
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurMethod != null) {
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            MSG_UNBIND_INPUT, mCurMethod));
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1041a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn
1042a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
1043a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                    MSG_SET_ACTIVE, 0, mCurClient));
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurClient.sessionRequested = false;
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurClient = null;
1048ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1049105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            hideInputMethodMenuLocked();
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1052ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getImeShowFlags() {
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int flags = 0;
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mShowForced) {
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags |= InputMethod.SHOW_FORCED
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    | InputMethod.SHOW_EXPLICIT;
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (mShowExplicitlyRequested) {
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags |= InputMethod.SHOW_EXPLICIT;
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return flags;
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1063ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getAppShowFlags() {
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int flags = 0;
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mShowForced) {
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags |= InputMethodManager.SHOW_FORCED;
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (!mShowExplicitlyRequested) {
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags |= InputMethodManager.SHOW_IMPLICIT;
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return flags;
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1073ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
10747663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn    InputBindResult attachNewInputLocked(boolean initial) {
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mBoundToMethod) {
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mBoundToMethod = true;
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final SessionState session = mCurClient.curSession;
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (initial) {
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            executeOrSendMessage(session.method, mCaller.obtainMessageOOO(
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MSG_START_INPUT, session, mCurInputContext, mCurAttribute));
10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            executeOrSendMessage(session.method, mCaller.obtainMessageOOO(
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MSG_RESTART_INPUT, session, mCurInputContext, mCurAttribute));
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mShowRequested) {
10898a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
10904df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            showCurrentInputLocked(getAppShowFlags(), null);
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10927663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn        return new InputBindResult(session.session, mCurId, mCurSeq);
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1094ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    InputBindResult startInputLocked(IInputMethodClient client,
10967663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn            IInputContext inputContext, EditorInfo attribute, int controlFlags) {
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // If no method is currently selected, do nothing.
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurMethodId == null) {
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mNoBinding;
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1101ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ClientState cs = mClients.get(client.asBinder());
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (cs == null) {
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("unknown client "
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + client.asBinder());
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1107ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mIWindowManager.inputMethodClientHasFocus(cs.client)) {
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Check with the window manager to make sure this client actually
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // has a window with focus.  If not, reject.  This is thread safe
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // because if the focus changes some time before or after, the
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // next client receiving focus that has any interest in input will
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // be calling through here after that change happens.
11158a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Starting input on non-focused client " + cs.client
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (RemoteException e) {
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1121ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11227663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn        return startInputUncheckedLocked(cs, inputContext, attribute, controlFlags);
11237663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn    }
11247663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn
11257663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn    InputBindResult startInputUncheckedLocked(ClientState cs,
11267663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn            IInputContext inputContext, EditorInfo attribute, int controlFlags) {
11277663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn        // If no method is currently selected, do nothing.
11287663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn        if (mCurMethodId == null) {
11297663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn            return mNoBinding;
11307663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn        }
11317663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn
1132bc7b6fc2a4b701596a2c8eecc4aeef522abeeafaJohn Spurlock        if (mCurClient == null) {
1133bc7b6fc2a4b701596a2c8eecc4aeef522abeeafaJohn Spurlock            mInputBoundToKeyguard = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
1134bc7b6fc2a4b701596a2c8eecc4aeef522abeeafaJohn Spurlock            if (DEBUG) {
1135bc7b6fc2a4b701596a2c8eecc4aeef522abeeafaJohn Spurlock                Slog.v(TAG, "New bind. keyguard = " +  mInputBoundToKeyguard);
1136bc7b6fc2a4b701596a2c8eecc4aeef522abeeafaJohn Spurlock            }
1137bc7b6fc2a4b701596a2c8eecc4aeef522abeeafaJohn Spurlock        }
1138bc7b6fc2a4b701596a2c8eecc4aeef522abeeafaJohn Spurlock
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurClient != cs) {
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If the client is changing, we need to switch over to the new
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // one.
1142b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            unbindCurrentClientLocked();
11438a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG, "switching to client: client = "
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + cs.client.asBinder());
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If the screen is on, inform the new client it is active
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mScreenOn) {
1148a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                executeOrSendMessage(cs.client, mCaller.obtainMessageIO(
1149a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                        MSG_SET_ACTIVE, mScreenOn ? 1 : 0, cs));
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1152ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Bump up the sequence for this client and attach it.
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurSeq++;
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurSeq <= 0) mCurSeq = 1;
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurClient = cs;
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurInputContext = inputContext;
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurAttribute = attribute;
1159ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check if the input method is changing.
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurId != null && mCurId.equals(mCurMethodId)) {
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (cs.curSession != null) {
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Fast case: if we are already connected to the input method,
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // then just return it.
11657663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                return attachNewInputLocked(
11667663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        (controlFlags&InputMethodManager.CONTROL_START_INITIAL) != 0);
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mHaveConnection) {
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurMethod != null) {
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!cs.sessionRequested) {
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        cs.sessionRequested = true;
11728a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                        if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                MSG_CREATE_SESSION, mCurMethod,
1175e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard                                new MethodCallback(mCurMethod, this)));
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Return to client, and we will get back with it when
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // we have had a session made for it.
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return new InputBindResult(null, mCurId, mCurSeq);
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (SystemClock.uptimeMillis()
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        < (mLastBindTime+TIME_TO_RECONNECT)) {
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // In this case we have connected to the service, but
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // don't yet have its interface.  If it hasn't been too
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // long since we did the connection, we'll return to
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // the client and wait to get the service interface so
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // we can report back.  If it has been too long, we want
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // to fall through so we can try a disconnect/reconnect
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // to see if we can get back in touch with the service.
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return new InputBindResult(null, mCurId, mCurSeq);
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
1191ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker                    EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
1192ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker                            mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1196ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1197a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        return startInputInnerLocked();
1198a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn    }
1199ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1200a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn    InputBindResult startInputInnerLocked() {
1201a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        if (mCurMethodId == null) {
1202a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            return mNoBinding;
1203a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        }
1204ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1205a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        if (!mSystemReady) {
1206a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            // If the system is not yet ready, we shouldn't be running third
1207a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            // party code.
1208cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn            return new InputBindResult(null, mCurMethodId, mCurSeq);
1209a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn        }
1210ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        InputMethodInfo info = mMethodMap.get(mCurMethodId);
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (info == null) {
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1215ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
12162ea9bae7121f1df5461437d7d08fa550cdf6e0b0Dianne Hackborn        unbindCurrentMethodLocked(false, true);
1217ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurIntent.setComponent(info.getComponent());
1220dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackborn        mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
1221dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackborn                com.android.internal.R.string.input_method_binding_label);
1222dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackborn        mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
1223dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackborn                mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
12244e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (bindCurrentInputMethodService(mCurIntent, this, Context.BIND_AUTO_CREATE
12252c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn                | Context.BIND_NOT_VISIBLE)) {
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLastBindTime = SystemClock.uptimeMillis();
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHaveConnection = true;
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurId = info.getId();
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurToken = new Binder();
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
12318a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurToken);
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mIWindowManager.addWindowToken(mCurToken,
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        WindowManager.LayoutParams.TYPE_INPUT_METHOD);
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new InputBindResult(null, mCurId, mCurSeq);
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurIntent = null;
12398a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            Slog.w(TAG, "Failure connecting to input method service: "
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + mCurIntent);
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1244ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1245e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public InputBindResult startInput(IInputMethodClient client,
12477663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn            IInputContext inputContext, EditorInfo attribute, int controlFlags) {
12484e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
12494e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return null;
12504e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final long ident = Binder.clearCallingIdentity();
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
12547663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                return startInputLocked(client, inputContext, attribute, controlFlags);
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Binder.restoreCallingIdentity(ident);
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1260ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1261e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void finishInput(IInputMethodClient client) {
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1264ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1265e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onServiceConnected(ComponentName name, IBinder service) {
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mCurMethod = IInputMethod.Stub.asInterface(service);
1270cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                if (mCurToken == null) {
12718a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.w(TAG, "Service connected without a token!");
12722ea9bae7121f1df5461437d7d08fa550cdf6e0b0Dianne Hackborn                    unbindCurrentMethodLocked(false, false);
1273cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                    return;
1274cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                }
12758a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
1276cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
1277cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                        MSG_ATTACH_TOKEN, mCurMethod, mCurToken));
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient != null) {
12798a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.v(TAG, "Creating first session while with client "
1280cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                            + mCurClient);
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
1282cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn                            MSG_CREATE_SESSION, mCurMethod,
1283e0d32a60da29e133e5b4ff46133628476d83872cJean Chalard                            new MethodCallback(mCurMethod, this)));
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void onSessionCreated(IInputMethod method, IInputMethodSession session) {
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mCurMethod != null && method != null
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && mCurMethod.asBinder() == method.asBinder()) {
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient != null) {
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCurClient.curSession = new SessionState(mCurClient,
12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            method, session);
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCurClient.sessionRequested = false;
12977663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                    InputBindResult res = attachNewInputLocked(true);
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (res.method != null) {
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                MSG_BIND_METHOD, mCurClient.client, res));
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1306ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
13072ea9bae7121f1df5461437d7d08fa550cdf6e0b0Dianne Hackborn    void unbindCurrentMethodLocked(boolean reportToClient, boolean savePosition) {
13082c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn        if (mVisibleBound) {
13092c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn            mContext.unbindService(mVisibleConnection);
13102c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn            mVisibleBound = false;
13112c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn        }
13122c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn
1313b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        if (mHaveConnection) {
1314b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            mContext.unbindService(this);
1315b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            mHaveConnection = false;
1316b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        }
1317ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1318b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        if (mCurToken != null) {
1319b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            try {
13208a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Removing window token: " + mCurToken);
13212ea9bae7121f1df5461437d7d08fa550cdf6e0b0Dianne Hackborn                if ((mImeWindowVis & InputMethodService.IME_ACTIVE) != 0 && savePosition) {
1322e0a99414bd3737ad976bf4a040c184bebd8e2e3dsatok                    // The current IME is shown. Hence an IME switch (transition) is happening.
1323e0a99414bd3737ad976bf4a040c184bebd8e2e3dsatok                    mWindowManagerService.saveLastInputMethodWindowForTransition();
1324e0a99414bd3737ad976bf4a040c184bebd8e2e3dsatok                }
1325b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                mIWindowManager.removeWindowToken(mCurToken);
1326b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            } catch (RemoteException e) {
1327b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            }
1328b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            mCurToken = null;
1329b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        }
1330ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1331105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mCurId = null;
1332b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        clearCurMethodLocked();
1333ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1334b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        if (reportToClient && mCurClient != null) {
1335b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
1336b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
1337b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        }
1338b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    }
1339b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
13400c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor    private void finishSession(SessionState sessionState) {
13410c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor        if (sessionState != null && sessionState.session != null) {
13420c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            try {
13430c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor                sessionState.session.finishSession();
13440c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            } catch (RemoteException e) {
13459d0f6dfdc1ac0b9374acf51572f273e9c9bbc9f9Jean-Baptiste Queru                Slog.w(TAG, "Session failed to close due to remote exception", e);
134615452a487a4c0274f4217cd060aa54446f30a8f3satok                setImeWindowVisibilityStatusHiddenLocked();
13470c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            }
13480c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor        }
13490c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor    }
1350ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1351b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    void clearCurMethodLocked() {
13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurMethod != null) {
13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (ClientState cs : mClients.values()) {
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                cs.sessionRequested = false;
13550c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor                finishSession(cs.curSession);
13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                cs.curSession = null;
13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13580c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor
13590c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            finishSession(mEnabledSession);
13600c33ed2992b2eb484c229fd3322df14d97c10caaDevin Taylor            mEnabledSession = null;
13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurMethod = null;
13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1363661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn        if (mStatusBar != null) {
1364661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn            mStatusBar.setIconVisibility("ime", false);
1365661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn        }
13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1367ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1368e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onServiceDisconnected(ComponentName name) {
13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
13718a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG, "Service disconnected: " + name
13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mCurIntent=" + mCurIntent);
13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mCurMethod != null && mCurIntent != null
13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && name.equals(mCurIntent.getComponent())) {
1375b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                clearCurMethodLocked();
13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // We consider this to be a new bind attempt, since the system
13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // should now try to restart the service for us.
13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLastBindTime = SystemClock.uptimeMillis();
13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mShowRequested = mInputShown;
13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mInputShown = false;
13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient != null) {
13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1389f9f01008624e2d28c15a90d942fa36f98c8c967dsatok    @Override
13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void updateStatusIcon(IBinder token, String packageName, int iconId) {
1391cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn        int uid = Binder.getCallingUid();
13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long ident = Binder.clearCallingIdentity();
13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (token == null || mCurToken != token) {
1395cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                Slog.w(TAG, "Ignoring setInputMethod of uid " + uid + " token: " + token);
13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1398ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (iconId == 0) {
14018a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
1402661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    if (mStatusBar != null) {
1403661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                        mStatusBar.setIconVisibility("ime", false);
1404661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    }
14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (packageName != null) {
14068a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
14076179ea3196e9306d3f14361fe9ef14191b1edba6Svetoslav Ganov                    CharSequence contentDescription = null;
14086179ea3196e9306d3f14361fe9ef14191b1edba6Svetoslav Ganov                    try {
14094e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        // Use PackageManager to load label
14104e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        final PackageManager packageManager = mContext.getPackageManager();
14116179ea3196e9306d3f14361fe9ef14191b1edba6Svetoslav Ganov                        contentDescription = packageManager.getApplicationLabel(
14124e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                mIPackageManager.getApplicationInfo(packageName, 0,
14134e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                        mSettings.getCurrentUserId()));
14144e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    } catch (RemoteException e) {
14156179ea3196e9306d3f14361fe9ef14191b1edba6Svetoslav Ganov                        /* ignore */
14166179ea3196e9306d3f14361fe9ef14191b1edba6Svetoslav Ganov                    }
1417661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    if (mStatusBar != null) {
1418661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                        mStatusBar.setIcon("ime", packageName, iconId, 0,
1419661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                                contentDescription  != null
1420661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                                        ? contentDescription.toString() : null);
1421661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                        mStatusBar.setIconVisibility("ime", true);
1422661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    }
14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14307cfc0ed21a3fafabafb40b38a8589808ad1517afsatok    private boolean needsToShowImeSwitchOngoingNotification() {
14317cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        if (!mShowOngoingImeSwitcherForPhones) return false;
14322c93efc9eb188532472edc9e0c3e1ab8121aa20dsatok        if (isScreenLocked()) return false;
14337cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        synchronized (mMethodMap) {
14347cfc0ed21a3fafabafb40b38a8589808ad1517afsatok            List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
14357cfc0ed21a3fafabafb40b38a8589808ad1517afsatok            final int N = imis.size();
1436b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            if (N > 2) return true;
1437b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            if (N < 1) return false;
1438b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            int nonAuxCount = 0;
1439b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            int auxCount = 0;
1440b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            InputMethodSubtype nonAuxSubtype = null;
1441b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            InputMethodSubtype auxSubtype = null;
14427cfc0ed21a3fafabafb40b38a8589808ad1517afsatok            for(int i = 0; i < N; ++i) {
14437cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                final InputMethodInfo imi = imis.get(i);
14447cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                final List<InputMethodSubtype> subtypes = getEnabledInputMethodSubtypeListLocked(
14457cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                        imi, true);
14467cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                final int subtypeCount = subtypes.size();
14477cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                if (subtypeCount == 0) {
1448b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                    ++nonAuxCount;
14497cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                } else {
14507cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                    for (int j = 0; j < subtypeCount; ++j) {
1451b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                        final InputMethodSubtype subtype = subtypes.get(j);
1452b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                        if (!subtype.isAuxiliary()) {
1453b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                            ++nonAuxCount;
1454b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                            nonAuxSubtype = subtype;
1455b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                        } else {
1456b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                            ++auxCount;
1457b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                            auxSubtype = subtype;
14587cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                        }
14597cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                    }
14607cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                }
14617cfc0ed21a3fafabafb40b38a8589808ad1517afsatok            }
1462b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            if (nonAuxCount > 1 || auxCount > 1) {
1463b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                return true;
1464b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            } else if (nonAuxCount == 1 && auxCount == 1) {
1465b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                if (nonAuxSubtype != null && auxSubtype != null
14669747f8977c55013e656a1e666a1647bb331954cesatok                        && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
14679747f8977c55013e656a1e666a1647bb331954cesatok                                || auxSubtype.overridesImplicitlyEnabledSubtype()
14689747f8977c55013e656a1e666a1647bb331954cesatok                                || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
1469b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                        && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
1470b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                    return false;
1471b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                }
1472b6359414adabab2d64acc8ccc9e3b9c1b800b303satok                return true;
1473b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            }
1474b6359414adabab2d64acc8ccc9e3b9c1b800b303satok            return false;
14757cfc0ed21a3fafabafb40b38a8589808ad1517afsatok        }
14767cfc0ed21a3fafabafb40b38a8589808ad1517afsatok    }
14777cfc0ed21a3fafabafb40b38a8589808ad1517afsatok
14784e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    // Caution! This method is called in this class. Handle multi-user carefully
1479dbf2950781ab0c4c0fc4ad9bd71b13c55ae6f471satok    @SuppressWarnings("deprecation")
1480f9f01008624e2d28c15a90d942fa36f98c8c967dsatok    @Override
1481857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato    public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
14824e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final long ident = Binder.clearCallingIdentity();
148306487a58be22b100daf3f950b9a1d25c3ea42aa2satok        try {
148406487a58be22b100daf3f950b9a1d25c3ea42aa2satok            if (token == null || mCurToken != token) {
14854e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                int uid = Binder.getCallingUid();
1486857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                Slog.w(TAG, "Ignoring setImeWindowStatus of uid " + uid + " token: " + token);
148706487a58be22b100daf3f950b9a1d25c3ea42aa2satok                return;
148806487a58be22b100daf3f950b9a1d25c3ea42aa2satok            }
148906487a58be22b100daf3f950b9a1d25c3ea42aa2satok
149006487a58be22b100daf3f950b9a1d25c3ea42aa2satok            synchronized (mMethodMap) {
1491857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                mImeWindowVis = vis;
1492857fd9b8562c29913e03ed29288bd1802d37dc60Joe Onorato                mBackDisposition = backDisposition;
1493661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                if (mStatusBar != null) {
1494661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    mStatusBar.setImeWindowStatus(token, vis, backDisposition);
1495661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                }
14967cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                final boolean iconVisibility = (vis & InputMethodService.IME_ACTIVE) != 0;
14975bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
14985bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                if (imi != null && iconVisibility && needsToShowImeSwitchOngoingNotification()) {
14994e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    // Used to load label
15007cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                    final PackageManager pm = mContext.getPackageManager();
15017cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                    final CharSequence title = mRes.getText(
15027cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                            com.android.internal.R.string.select_input_method);
15035bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                    final CharSequence imiLabel = imi.loadLabel(pm);
15045bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                    final CharSequence summary = mCurrentSubtype != null
15055bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                            ? TextUtils.concat(mCurrentSubtype.getDisplayName(mContext,
15065bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                                        imi.getPackageName(), imi.getServiceInfo().applicationInfo),
15075bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                                                (TextUtils.isEmpty(imiLabel) ?
150805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                                                        "" : " - " + imiLabel))
15095bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                            : imiLabel;
15105bc8e732bd831a308a5bc1720b0e4c9300d32f67satok
15117cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                    mImeSwitcherNotification.setLatestEventInfo(
15125bc8e732bd831a308a5bc1720b0e4c9300d32f67satok                            mContext, title, summary, mImeSwitchPendingIntent);
1513661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    if (mNotificationManager != null) {
1514135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        if (DEBUG) {
1515135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                            Slog.d(TAG, "--- show notification: label =  " + imiLabel
1516135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                                    + ", summary = " + summary);
1517135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        }
1518135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        mNotificationManager.notifyAsUser(null,
1519661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                                com.android.internal.R.string.select_input_method,
1520135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                                mImeSwitcherNotification, UserHandle.ALL);
1521661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                        mNotificationShown = true;
1522661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    }
15237cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                } else {
1524661cd52e0e1d527132eb1cae604d3e64da7ec0cbDianne Hackborn                    if (mNotificationShown && mNotificationManager != null) {
1525135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        if (DEBUG) {
1526135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                            Slog.d(TAG, "--- hide notification");
1527135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        }
1528135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                        mNotificationManager.cancelAsUser(null,
1529135e5fb71242b1151929e2ea7bf221ff421e6ad2Satoshi Kataoka                                com.android.internal.R.string.select_input_method, UserHandle.ALL);
15307cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                        mNotificationShown = false;
15317cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                    }
15327cfc0ed21a3fafabafb40b38a8589808ad1517afsatok                }
153306487a58be22b100daf3f950b9a1d25c3ea42aa2satok            }
153406487a58be22b100daf3f950b9a1d25c3ea42aa2satok        } finally {
153506487a58be22b100daf3f950b9a1d25c3ea42aa2satok            Binder.restoreCallingIdentity(ident);
153606487a58be22b100daf3f950b9a1d25c3ea42aa2satok        }
153706487a58be22b100daf3f950b9a1d25c3ea42aa2satok    }
153806487a58be22b100daf3f950b9a1d25c3ea42aa2satok
1539e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
1540f9f01008624e2d28c15a90d942fa36f98c8c967dsatok    public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) {
15414e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
15424e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
15434e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
1544f9f01008624e2d28c15a90d942fa36f98c8c967dsatok        synchronized (mMethodMap) {
1545f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
1546f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            for (int i = 0; i < spans.length; ++i) {
1547f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                SuggestionSpan ss = spans[i];
154842c5a1666c4e576ccd5974233513100aad2c1534satok                if (!TextUtils.isEmpty(ss.getNotificationTargetClassName())) {
1549f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                    mSecureSuggestionSpans.put(ss, currentImi);
155042c5a1666c4e576ccd5974233513100aad2c1534satok                    final InputMethodInfo targetImi = mSecureSuggestionSpans.get(ss);
1551f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                }
1552f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            }
1553f9f01008624e2d28c15a90d942fa36f98c8c967dsatok        }
1554f9f01008624e2d28c15a90d942fa36f98c8c967dsatok    }
1555f9f01008624e2d28c15a90d942fa36f98c8c967dsatok
1556e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
1557f9f01008624e2d28c15a90d942fa36f98c8c967dsatok    public boolean notifySuggestionPicked(SuggestionSpan span, String originalString, int index) {
15584e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
15594e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
15604e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
1561f9f01008624e2d28c15a90d942fa36f98c8c967dsatok        synchronized (mMethodMap) {
1562f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            final InputMethodInfo targetImi = mSecureSuggestionSpans.get(span);
1563f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            // TODO: Do not send the intent if the process of the targetImi is already dead.
1564f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            if (targetImi != null) {
1565f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                final String[] suggestions = span.getSuggestions();
1566f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                if (index < 0 || index >= suggestions.length) return false;
156742c5a1666c4e576ccd5974233513100aad2c1534satok                final String className = span.getNotificationTargetClassName();
1568f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                final Intent intent = new Intent();
1569f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                // Ensures that only a class in the original IME package will receive the
1570f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                // notification.
157142c5a1666c4e576ccd5974233513100aad2c1534satok                intent.setClassName(targetImi.getPackageName(), className);
1572f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                intent.setAction(SuggestionSpan.ACTION_SUGGESTION_PICKED);
1573f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_BEFORE, originalString);
1574f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_AFTER, suggestions[index]);
1575f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_HASHCODE, span.hashCode());
1576f043de93ebb5178fb4b5c8f14e143c6f08bcc26fAmith Yamasani                final long ident = Binder.clearCallingIdentity();
1577f043de93ebb5178fb4b5c8f14e143c6f08bcc26fAmith Yamasani                try {
1578f043de93ebb5178fb4b5c8f14e143c6f08bcc26fAmith Yamasani                    mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
1579f043de93ebb5178fb4b5c8f14e143c6f08bcc26fAmith Yamasani                } finally {
1580f043de93ebb5178fb4b5c8f14e143c6f08bcc26fAmith Yamasani                    Binder.restoreCallingIdentity(ident);
1581f043de93ebb5178fb4b5c8f14e143c6f08bcc26fAmith Yamasani                }
1582f9f01008624e2d28c15a90d942fa36f98c8c967dsatok                return true;
1583f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            }
1584f9f01008624e2d28c15a90d942fa36f98c8c967dsatok        }
1585f9f01008624e2d28c15a90d942fa36f98c8c967dsatok        return false;
1586f9f01008624e2d28c15a90d942fa36f98c8c967dsatok    }
1587f9f01008624e2d28c15a90d942fa36f98c8c967dsatok
15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void updateFromSettingsLocked() {
1589b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and
1590b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        // ENABLED_INPUT_METHODS is taking care of keeping them correctly in
1591b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        // sync, so we will never have a DEFAULT_INPUT_METHOD that is not
1592b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        // enabled.
15934e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        String id = mSettings.getSelectedInputMethod();
159403eb319a3a7fe6fe9ab9eba6fc1f727285850906satok        // There is no input method selected, try to choose new applicable input method.
159503eb319a3a7fe6fe9ab9eba6fc1f727285850906satok        if (TextUtils.isEmpty(id) && chooseNewDefaultIMELocked()) {
15964e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            id = mSettings.getSelectedInputMethod();
159703eb319a3a7fe6fe9ab9eba6fc1f727285850906satok        }
159803eb319a3a7fe6fe9ab9eba6fc1f727285850906satok        if (!TextUtils.isEmpty(id)) {
15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
1600ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                setInputMethodLocked(id, getSelectedInputMethodSubtypeId(id));
16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IllegalArgumentException e) {
16028a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Unknown input method from prefs: " + id, e);
1603105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                mCurMethodId = null;
16042ea9bae7121f1df5461437d7d08fa550cdf6e0b0Dianne Hackborn                unbindCurrentMethodLocked(true, false);
16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1606f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            mShortcutInputMethodsAndSubtypes.clear();
1607b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        } else {
1608b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            // There is no longer an input method set, so stop any current one.
1609105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mCurMethodId = null;
16102ea9bae7121f1df5461437d7d08fa550cdf6e0b0Dianne Hackborn            unbindCurrentMethodLocked(true, false);
16119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1613ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1614ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    /* package */ void setInputMethodLocked(String id, int subtypeId) {
16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        InputMethodInfo info = mMethodMap.get(id);
16169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (info == null) {
1617913a8925c07e854a80bf5df87561f290d3a56d61satok            throw new IllegalArgumentException("Unknown id: " + id);
16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1619ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1620d81e950265356c81276b73da68a535ffa48d72f0satok        // See if we need to notify a subtype change within the same IME.
16219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (id.equals(mCurMethodId)) {
1622d81e950265356c81276b73da68a535ffa48d72f0satok            final int subtypeCount = info.getSubtypeCount();
1623d81e950265356c81276b73da68a535ffa48d72f0satok            if (subtypeCount <= 0) {
1624d81e950265356c81276b73da68a535ffa48d72f0satok                return;
1625d81e950265356c81276b73da68a535ffa48d72f0satok            }
1626d81e950265356c81276b73da68a535ffa48d72f0satok            final InputMethodSubtype oldSubtype = mCurrentSubtype;
1627d81e950265356c81276b73da68a535ffa48d72f0satok            final InputMethodSubtype newSubtype;
1628d81e950265356c81276b73da68a535ffa48d72f0satok            if (subtypeId >= 0 && subtypeId < subtypeCount) {
1629d81e950265356c81276b73da68a535ffa48d72f0satok                newSubtype = info.getSubtypeAt(subtypeId);
1630d81e950265356c81276b73da68a535ffa48d72f0satok            } else {
1631d81e950265356c81276b73da68a535ffa48d72f0satok                // If subtype is null, try to find the most applicable one from
1632d81e950265356c81276b73da68a535ffa48d72f0satok                // getCurrentInputMethodSubtype.
16334e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                newSubtype = getCurrentInputMethodSubtypeLocked();
1634d81e950265356c81276b73da68a535ffa48d72f0satok            }
1635d81e950265356c81276b73da68a535ffa48d72f0satok            if (newSubtype == null || oldSubtype == null) {
1636d81e950265356c81276b73da68a535ffa48d72f0satok                Slog.w(TAG, "Illegal subtype state: old subtype = " + oldSubtype
1637d81e950265356c81276b73da68a535ffa48d72f0satok                        + ", new subtype = " + newSubtype);
1638d81e950265356c81276b73da68a535ffa48d72f0satok                return;
1639d81e950265356c81276b73da68a535ffa48d72f0satok            }
1640d81e950265356c81276b73da68a535ffa48d72f0satok            if (newSubtype != oldSubtype) {
1641d81e950265356c81276b73da68a535ffa48d72f0satok                setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
1642d81e950265356c81276b73da68a535ffa48d72f0satok                if (mCurMethod != null) {
1643d81e950265356c81276b73da68a535ffa48d72f0satok                    try {
1644d81e950265356c81276b73da68a535ffa48d72f0satok                        refreshImeWindowVisibilityLocked();
1645d81e950265356c81276b73da68a535ffa48d72f0satok                        mCurMethod.changeInputMethodSubtype(newSubtype);
1646d81e950265356c81276b73da68a535ffa48d72f0satok                    } catch (RemoteException e) {
1647d81e950265356c81276b73da68a535ffa48d72f0satok                        Slog.w(TAG, "Failed to call changeInputMethodSubtype");
1648ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    }
1649ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                }
1650ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            }
16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1653ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1654d81e950265356c81276b73da68a535ffa48d72f0satok        // Changing to a different IME.
16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long ident = Binder.clearCallingIdentity();
16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
1657ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            // Set a subtype to this input method.
1658ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            // subtypeId the name of a subtype which will be set.
1659723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            setSelectedInputMethodAndSubtypeLocked(info, subtypeId, false);
1660723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
1661723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // because mCurMethodId is stored as a history in
1662723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // setSelectedInputMethodAndSubtypeLocked().
1663723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mCurMethodId = id;
16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (ActivityManagerNative.isSystemReady()) {
16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
16671c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                intent.putExtra("input_method_id", id);
1669cd75706117432e33d11639e675bcff50479a6bb9Amith Yamasani                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1671b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            unbindCurrentClientLocked();
16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1676ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
167742c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
16784df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    public boolean showSoftInput(IInputMethodClient client, int flags,
16794df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            ResultReceiver resultReceiver) {
16804e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
16814e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
16824e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
1683cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn        int uid = Binder.getCallingUid();
16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long ident = Binder.clearCallingIdentity();
16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient == null || client == null
16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        || mCurClient.client.asBinder() != client.asBinder()) {
16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // We need to check if this is the current client with
16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // focus in the window manager, to allow this call to
16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // be made before input is started in it.
16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (!mIWindowManager.inputMethodClientHasFocus(client)) {
1694cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                            Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
16954df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            return false;
16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
16979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (RemoteException e) {
16984df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                        return false;
16999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
17009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1701ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
17028a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
17034df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                return showCurrentInputLocked(flags, resultReceiver);
17049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1709ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
17104df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    boolean showCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mShowRequested = true;
17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mShowExplicitlyRequested = true;
17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
17169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mShowExplicitlyRequested = true;
17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mShowForced = true;
17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1719ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
1720cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn        if (!mSystemReady) {
1721cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn            return false;
1722cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn        }
1723ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
17244df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        boolean res = false;
17259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCurMethod != null) {
17264df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
17274df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod,
17284df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    resultReceiver));
17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mInputShown = true;
17302c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn            if (mHaveConnection && !mVisibleBound) {
17314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                bindCurrentInputMethodService(
17324e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        mCurIntent, mVisibleConnection, Context.BIND_AUTO_CREATE);
17332c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn                mVisibleBound = true;
17342c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn            }
17354df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            res = true;
17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (mHaveConnection && SystemClock.uptimeMillis()
173759b424c3b6121c9579fc5efcc785ba084072a5casatok                >= (mLastBindTime+TIME_TO_RECONNECT)) {
17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // The client has asked to have the input method shown, but
17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // we have been sitting here too long with a connection to the
17409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // service and no interface received, so let's disconnect/connect
17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // to try to prod things along.
1742ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker            EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId,
17439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SystemClock.uptimeMillis()-mLastBindTime,1);
174459b424c3b6121c9579fc5efcc785ba084072a5casatok            Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()");
17459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.unbindService(this);
17464e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            bindCurrentInputMethodService(mCurIntent, this, Context.BIND_AUTO_CREATE
17472c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn                    | Context.BIND_NOT_VISIBLE);
17484e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        } else {
17494e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
17504e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "Can't show input: connection = " + mHaveConnection + ", time = "
17514e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        + ((mLastBindTime+TIME_TO_RECONNECT) - SystemClock.uptimeMillis()));
17524e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1754ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
17554df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        return res;
17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1757ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
175842c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
17594df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    public boolean hideSoftInput(IInputMethodClient client, int flags,
17604df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            ResultReceiver resultReceiver) {
17614e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
17624e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
17634e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
1764cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn        int uid = Binder.getCallingUid();
17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long ident = Binder.clearCallingIdentity();
17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
17689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCurClient == null || client == null
17699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        || mCurClient.client.asBinder() != client.asBinder()) {
17709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
17719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // We need to check if this is the current client with
17729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // focus in the window manager, to allow this call to
17739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // be made before input is started in it.
17749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (!mIWindowManager.inputMethodClientHasFocus(client)) {
1775cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                            if (DEBUG) Slog.w(TAG, "Ignoring hideSoftInput of uid "
1776cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                                    + uid + ": " + client);
177715452a487a4c0274f4217cd060aa54446f30a8f3satok                            setImeWindowVisibilityStatusHiddenLocked();
17784df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            return false;
17799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
17809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (RemoteException e) {
178115452a487a4c0274f4217cd060aa54446f30a8f3satok                        setImeWindowVisibilityStatusHiddenLocked();
17824df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                        return false;
17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1785ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
17868a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
17874df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                return hideCurrentInputLocked(flags, resultReceiver);
17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
17919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1793ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
17944df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                && (mShowExplicitlyRequested || mShowForced)) {
17978a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG,
17989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    "Not hiding: explicit show not cancelled by non-explicit hide");
17994df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            return false;
18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
18028a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.v(TAG,
18039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    "Not hiding: forced show not cancelled by not-always hide");
18044df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            return false;
18059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18064df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        boolean res;
18079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mInputShown && mCurMethod != null) {
18084df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
18094df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    MSG_HIDE_SOFT_INPUT, mCurMethod, resultReceiver));
18104df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            res = true;
18114df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        } else {
18124df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            res = false;
18139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18142c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn        if (mHaveConnection && mVisibleBound) {
18152c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn            mContext.unbindService(mVisibleConnection);
18162c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn            mVisibleBound = false;
18172c84cfc001fb92a71811bf7384b7f865ff31ff9dDianne Hackborn        }
18189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mInputShown = false;
18199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mShowRequested = false;
18209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mShowExplicitlyRequested = false;
18219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mShowForced = false;
18224df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        return res;
18239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1824ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
182542c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
18267663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn    public InputBindResult windowGainedFocus(IInputMethodClient client, IBinder windowToken,
18277663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn            int controlFlags, int softInputMode, int windowFlags,
18287663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn            EditorInfo attribute, IInputContext inputContext) {
18298d03305b576e429909e420c235163c2be1aae732Satoshi Kataoka        // Needs to check the validity before clearing calling identity
18308d03305b576e429909e420c235163c2be1aae732Satoshi Kataoka        final boolean calledFromValidUser = calledFromValidUser();
18318d03305b576e429909e420c235163c2be1aae732Satoshi Kataoka
18327663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn        InputBindResult res = null;
18339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long ident = Binder.clearCallingIdentity();
18349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
18359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mMethodMap) {
18368a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "windowGainedFocus: " + client.asBinder()
18377663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        + " controlFlags=#" + Integer.toHexString(controlFlags)
18389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + " softInputMode=#" + Integer.toHexString(softInputMode)
18397663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        + " windowFlags=#" + Integer.toHexString(windowFlags));
1840ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
18417663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                ClientState cs = mClients.get(client.asBinder());
18427663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                if (cs == null) {
18437663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                    throw new IllegalArgumentException("unknown client "
18447663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            + client.asBinder());
18457663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                }
18467663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn
18477663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                try {
18487663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                    if (!mIWindowManager.inputMethodClientHasFocus(cs.client)) {
18497663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        // Check with the window manager to make sure this client actually
18507663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        // has a window with focus.  If not, reject.  This is thread safe
18517663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        // because if the focus changes some time before or after, the
18527663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        // next client receiving focus that has any interest in input will
18537663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        // be calling through here after that change happens.
18547663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        Slog.w(TAG, "Focus gain on non-focused client " + cs.client
18557663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
18567663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        return null;
18579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
18587663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                } catch (RemoteException e) {
18599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1860ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
18618d03305b576e429909e420c235163c2be1aae732Satoshi Kataoka                if (!calledFromValidUser) {
18628d03305b576e429909e420c235163c2be1aae732Satoshi Kataoka                    Slog.w(TAG, "A background user is requesting window. Hiding IME.");
18638d03305b576e429909e420c235163c2be1aae732Satoshi Kataoka                    Slog.w(TAG, "If you want to interect with IME, you need "
18648d03305b576e429909e420c235163c2be1aae732Satoshi Kataoka                            + "android.permission.INTERACT_ACROSS_USERS_FULL");
18658d03305b576e429909e420c235163c2be1aae732Satoshi Kataoka                    hideCurrentInputLocked(0, null);
18668d03305b576e429909e420c235163c2be1aae732Satoshi Kataoka                    return null;
18678d03305b576e429909e420c235163c2be1aae732Satoshi Kataoka                }
18688d03305b576e429909e420c235163c2be1aae732Satoshi Kataoka
1869b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                if (mCurFocusedWindow == windowToken) {
1870ac92087a9a1c464d4b0a58c82dae01cbaa088e89Dianne Hackborn                    Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
18713573950e0b30178dc963de3fa00aba2ebcfd552dSatoshi Kataoka                            + " attribute=" + attribute + ", token = " + windowToken);
18727663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                    if (attribute != null) {
18737663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        return startInputUncheckedLocked(cs, inputContext, attribute,
18747663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                controlFlags);
18757663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                    }
18767663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                    return null;
1877b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
1878b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                mCurFocusedWindow = windowToken;
1879ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
18807d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // Should we auto-show the IME even if the caller has not
18817d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // specified what should be done with it?
18827d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // We only do this automatically if the window can resize
18837d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // to accommodate the IME (so what the user sees will give
18847d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // them good context without input information being obscured
18857d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // by the IME) or if running on a large screen where there
18867d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                // is more room for the target window + IME.
18877d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                final boolean doAutoShow =
18887d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                        (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
18897d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                                == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
18907d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                        || mRes.getConfiguration().isLayoutSizeAtLeast(
18917d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                                Configuration.SCREENLAYOUT_SIZE_LARGE);
18927663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                final boolean isTextEditor =
18937663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        (controlFlags&InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR) != 0;
18947663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn
18957663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                // We want to start input before showing the IME, but after closing
18967663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                // it.  We want to do this after closing it to help the IME disappear
18977663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                // more quickly (not get stuck behind it initializing itself for the
18987663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                // new focused input, even if its window wants to hide the IME).
18997663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                boolean didStart = false;
19007d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn
19019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
19029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
19037d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                        if (!isTextEditor || !doAutoShow) {
19049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (WindowManager.LayoutParams.mayUseInputMethod(windowFlags)) {
19059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                // There is no focus view, and this window will
19069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                // be behind any soft input window, so hide the
19079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                // soft input window if it is shown.
19088a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                                if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
19094df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                                hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
19109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
19117d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                        } else if (isTextEditor && doAutoShow && (softInputMode &
19127d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
19139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // There is a focus view, and we are navigating forward
19149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // into the window, so show the input window for the user.
19157663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            // We only do this automatically if the window can resize
19167663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            // to accommodate the IME (so what the user sees will give
19177d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                            // them good context without input information being obscured
19187d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                            // by the IME) or if running on a large screen where there
19197d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn                            // is more room for the target window + IME.
19208a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
19217663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            if (attribute != null) {
19227663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                res = startInputUncheckedLocked(cs, inputContext, attribute,
19237663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                        controlFlags);
19247663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                didStart = true;
19257663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            }
19264df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
19279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
19289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
19299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
19309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // Do nothing.
19319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
19329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
19339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if ((softInputMode &
19349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
19358a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
19364df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            hideCurrentInputLocked(0, null);
19379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
19389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
19399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
19408a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                        if (DEBUG) Slog.v(TAG, "Window asks to hide input");
19414df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                        hideCurrentInputLocked(0, null);
19429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
19439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
19449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if ((softInputMode &
19459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
19468a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                            if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
19477663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            if (attribute != null) {
19487663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                res = startInputUncheckedLocked(cs, inputContext, attribute,
19497663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                        controlFlags);
19507663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                didStart = true;
19517663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            }
19524df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
19539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
19549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
19559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
19568a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                        if (DEBUG) Slog.v(TAG, "Window asks to always show input");
19577663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        if (attribute != null) {
19587663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            res = startInputUncheckedLocked(cs, inputContext, attribute,
19597663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                                    controlFlags);
19607663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            didStart = true;
19617663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                        }
19624df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                        showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
19639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
19649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
19657663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn
19667663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                if (!didStart && attribute != null) {
19677663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                    res = startInputUncheckedLocked(cs, inputContext, attribute,
19687663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                            controlFlags);
19697663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn                }
19709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
19729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(ident);
19739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19747663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn
19757663d80f6b6fd6ca7a736c3802013a09c0abdeb9Dianne Hackborn        return res;
19769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1977ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
197842c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
19799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void showInputMethodPickerFromClient(IInputMethodClient client) {
19804e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
19814e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
19824e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
19839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
19849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mCurClient == null || client == null
19859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    || mCurClient.client.asBinder() != client.asBinder()) {
198647a44916e2fb33cf4751906386d5f5c903b28d8bsatok                Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
1987cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                        + Binder.getCallingUid() + ": " + client);
19889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1990440aab54cab106030f1edafea4dec1f9d8624f9bsatok            // Always call subtype picker, because subtype picker is a superset of input method
1991440aab54cab106030f1edafea4dec1f9d8624f9bsatok            // picker.
1992ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            mHandler.sendEmptyMessage(MSG_SHOW_IM_SUBTYPE_PICKER);
1993ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        }
1994ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
1995ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
199642c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
19979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setInputMethod(IBinder token, String id) {
19984e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
19994e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
20004e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
20012820351489537698ad153c6397edf3270455edc5satok        setInputMethodWithSubtypeId(token, id, NOT_A_SUBTYPE_ID);
20022820351489537698ad153c6397edf3270455edc5satok    }
20032820351489537698ad153c6397edf3270455edc5satok
200442c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
20052820351489537698ad153c6397edf3270455edc5satok    public void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) {
20064e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
20074e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
20084e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
20092820351489537698ad153c6397edf3270455edc5satok        synchronized (mMethodMap) {
20102820351489537698ad153c6397edf3270455edc5satok            if (subtype != null) {
20112820351489537698ad153c6397edf3270455edc5satok                setInputMethodWithSubtypeId(token, id, getSubtypeIdFromHashCode(
20122820351489537698ad153c6397edf3270455edc5satok                        mMethodMap.get(id), subtype.hashCode()));
20132820351489537698ad153c6397edf3270455edc5satok            } else {
20142820351489537698ad153c6397edf3270455edc5satok                setInputMethod(token, id);
20152820351489537698ad153c6397edf3270455edc5satok            }
20162820351489537698ad153c6397edf3270455edc5satok        }
2017ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
2018ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
201942c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
2020b416a71e56cdd50742eb897366a140775aa4cd61satok    public void showInputMethodAndSubtypeEnablerFromClient(
2021217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok            IInputMethodClient client, String inputMethodId) {
20224e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
20234e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
20244e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
2025b416a71e56cdd50742eb897366a140775aa4cd61satok        synchronized (mMethodMap) {
2026b416a71e56cdd50742eb897366a140775aa4cd61satok            if (mCurClient == null || client == null
2027b416a71e56cdd50742eb897366a140775aa4cd61satok                || mCurClient.client.asBinder() != client.asBinder()) {
2028b416a71e56cdd50742eb897366a140775aa4cd61satok                Slog.w(TAG, "Ignoring showInputMethodAndSubtypeEnablerFromClient of: " + client);
2029b416a71e56cdd50742eb897366a140775aa4cd61satok            }
20307fee71f66afef6421b92fa48e63d4bc73f5d0c27satok            executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
20317fee71f66afef6421b92fa48e63d4bc73f5d0c27satok                    MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
2032b416a71e56cdd50742eb897366a140775aa4cd61satok        }
2033b416a71e56cdd50742eb897366a140775aa4cd61satok    }
2034b416a71e56cdd50742eb897366a140775aa4cd61satok
20354fc87d61c29886c848789208c9e32ba9ac4e5dd3satok    @Override
2036735cf38b8c7f8f91ad087511e44fe79018fa61d6satok    public boolean switchToLastInputMethod(IBinder token) {
20374e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
20384e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
20394e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
2040735cf38b8c7f8f91ad087511e44fe79018fa61d6satok        synchronized (mMethodMap) {
2041c445bcd0bce630948ee029d7c70b28226f0b6c9csatok            final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
20424fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            final InputMethodInfo lastImi;
2043208d5634047111811de16fb63c43d0bc8b4fe6desatok            if (lastIme != null) {
20444fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                lastImi = mMethodMap.get(lastIme.first);
20454fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            } else {
20464fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                lastImi = null;
20474fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            }
20484fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            String targetLastImiId = null;
20494fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            int subtypeId = NOT_A_SUBTYPE_ID;
20504fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            if (lastIme != null && lastImi != null) {
20514fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                final boolean imiIdIsSame = lastImi.getId().equals(mCurMethodId);
20524fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                final int lastSubtypeHash = Integer.valueOf(lastIme.second);
20534fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                final int currentSubtypeHash = mCurrentSubtype == null ? NOT_A_SUBTYPE_ID
20544fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                        : mCurrentSubtype.hashCode();
20554fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                // If the last IME is the same as the current IME and the last subtype is not
20564fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                // defined, there is no need to switch to the last IME.
20574fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                if (!imiIdIsSame || lastSubtypeHash != currentSubtypeHash) {
20584fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                    targetLastImiId = lastIme.first;
20594fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                    subtypeId = getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
20604fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                }
20614fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            }
20624fc87d61c29886c848789208c9e32ba9ac4e5dd3satok
20634fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            if (TextUtils.isEmpty(targetLastImiId) && !canAddToLastInputMethod(mCurrentSubtype)) {
20644fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                // This is a safety net. If the currentSubtype can't be added to the history
20654fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                // and the framework couldn't find the last ime, we will make the last ime be
20664fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                // the most applicable enabled keyboard subtype of the system imes.
20674fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                final List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
20684fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                if (enabled != null) {
20694fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                    final int N = enabled.size();
20704fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                    final String locale = mCurrentSubtype == null
20714fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                            ? mRes.getConfiguration().locale.toString()
20724fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                            : mCurrentSubtype.getLocale();
20734fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                    for (int i = 0; i < N; ++i) {
20744fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                        final InputMethodInfo imi = enabled.get(i);
20754fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                        if (imi.getSubtypeCount() > 0 && isSystemIme(imi)) {
20764fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                            InputMethodSubtype keyboardSubtype =
20774fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                    findLastResortApplicableSubtypeLocked(mRes, getSubtypes(imi),
20784fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                            SUBTYPE_MODE_KEYBOARD, locale, true);
20794fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                            if (keyboardSubtype != null) {
20804fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                targetLastImiId = imi.getId();
20814fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                subtypeId = getSubtypeIdFromHashCode(
20824fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                        imi, keyboardSubtype.hashCode());
20834fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                if(keyboardSubtype.getLocale().equals(locale)) {
20844fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                    break;
20854fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                                }
20864fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                            }
20874fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                        }
20884fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                    }
20894fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                }
20904fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            }
2091c445bcd0bce630948ee029d7c70b28226f0b6c9csatok
20924fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            if (!TextUtils.isEmpty(targetLastImiId)) {
2093c445bcd0bce630948ee029d7c70b28226f0b6c9csatok                if (DEBUG) {
20944fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                    Slog.d(TAG, "Switch to: " + lastImi.getId() + ", " + lastIme.second
20954fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                            + ", from: " + mCurMethodId + ", " + subtypeId);
2096735cf38b8c7f8f91ad087511e44fe79018fa61d6satok                }
20974fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                setInputMethodWithSubtypeId(token, targetLastImiId, subtypeId);
2098c445bcd0bce630948ee029d7c70b28226f0b6c9csatok                return true;
20994fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            } else {
21004fc87d61c29886c848789208c9e32ba9ac4e5dd3satok                return false;
2101735cf38b8c7f8f91ad087511e44fe79018fa61d6satok            }
2102735cf38b8c7f8f91ad087511e44fe79018fa61d6satok        }
2103735cf38b8c7f8f91ad087511e44fe79018fa61d6satok    }
2104735cf38b8c7f8f91ad087511e44fe79018fa61d6satok
2105e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
2106688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok    public boolean switchToNextInputMethod(IBinder token, boolean onlyCurrentIme) {
21074e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
21084e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
21094e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
2110688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        synchronized (mMethodMap) {
2111688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            final ImeSubtypeListItem nextSubtype = mImListManager.getNextInputMethod(
2112688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype);
2113688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            if (nextSubtype == null) {
2114688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                return false;
2115688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            }
2116688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            setInputMethodWithSubtypeId(token, nextSubtype.mImi.getId(), nextSubtype.mSubtypeId);
2117688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            return true;
2118688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        }
2119688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok    }
2120688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok
2121688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok    @Override
212268f1b78b7b9139a0e34285ff641a664e664a14b8satok    public InputMethodSubtype getLastInputMethodSubtype() {
21234e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
21244e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return null;
21254e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
212668f1b78b7b9139a0e34285ff641a664e664a14b8satok        synchronized (mMethodMap) {
212768f1b78b7b9139a0e34285ff641a664e664a14b8satok            final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
212868f1b78b7b9139a0e34285ff641a664e664a14b8satok            // TODO: Handle the case of the last IME with no subtypes
212968f1b78b7b9139a0e34285ff641a664e664a14b8satok            if (lastIme == null || TextUtils.isEmpty(lastIme.first)
213068f1b78b7b9139a0e34285ff641a664e664a14b8satok                    || TextUtils.isEmpty(lastIme.second)) return null;
213168f1b78b7b9139a0e34285ff641a664e664a14b8satok            final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
213268f1b78b7b9139a0e34285ff641a664e664a14b8satok            if (lastImi == null) return null;
213368f1b78b7b9139a0e34285ff641a664e664a14b8satok            try {
213468f1b78b7b9139a0e34285ff641a664e664a14b8satok                final int lastSubtypeHash = Integer.valueOf(lastIme.second);
21350e7d7d632309409e2bc51d5317cf7a92a7541433satok                final int lastSubtypeId = getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
21360e7d7d632309409e2bc51d5317cf7a92a7541433satok                if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
21370e7d7d632309409e2bc51d5317cf7a92a7541433satok                    return null;
21380e7d7d632309409e2bc51d5317cf7a92a7541433satok                }
21390e7d7d632309409e2bc51d5317cf7a92a7541433satok                return lastImi.getSubtypeAt(lastSubtypeId);
214068f1b78b7b9139a0e34285ff641a664e664a14b8satok            } catch (NumberFormatException e) {
214168f1b78b7b9139a0e34285ff641a664e664a14b8satok                return null;
214268f1b78b7b9139a0e34285ff641a664e664a14b8satok            }
214368f1b78b7b9139a0e34285ff641a664e664a14b8satok        }
214468f1b78b7b9139a0e34285ff641a664e664a14b8satok    }
214568f1b78b7b9139a0e34285ff641a664e664a14b8satok
2146e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
2147ee5e77cafec2eae70890abdcc1646ed39b06edddsatok    public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
21484e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
21494e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
21504e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
215191e88122cf28a48fd2e2260da7d3d87dd437227asatok        // By this IPC call, only a process which shares the same uid with the IME can add
215291e88122cf28a48fd2e2260da7d3d87dd437227asatok        // additional input method subtypes to the IME.
2153ee5e77cafec2eae70890abdcc1646ed39b06edddsatok        if (TextUtils.isEmpty(imiId) || subtypes == null || subtypes.length == 0) return;
2154e7c6998e0a953ae55487d4fe122739646f9280aasatok        synchronized (mMethodMap) {
215591e88122cf28a48fd2e2260da7d3d87dd437227asatok            final InputMethodInfo imi = mMethodMap.get(imiId);
2156ee5e77cafec2eae70890abdcc1646ed39b06edddsatok            if (imi == null) return;
21574e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            final String[] packageInfos;
21584e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            try {
21594e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                packageInfos = mIPackageManager.getPackagesForUid(Binder.getCallingUid());
21604e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            } catch (RemoteException e) {
21614e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.e(TAG, "Failed to get package infos");
21624e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                return;
21634e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
216491e88122cf28a48fd2e2260da7d3d87dd437227asatok            if (packageInfos != null) {
216591e88122cf28a48fd2e2260da7d3d87dd437227asatok                final int packageNum = packageInfos.length;
216691e88122cf28a48fd2e2260da7d3d87dd437227asatok                for (int i = 0; i < packageNum; ++i) {
216791e88122cf28a48fd2e2260da7d3d87dd437227asatok                    if (packageInfos[i].equals(imi.getPackageName())) {
216891e88122cf28a48fd2e2260da7d3d87dd437227asatok                        mFileManager.addInputMethodSubtypes(imi, subtypes);
2169c593380d1bccbfbd45c404954b2670b65acc287fsatok                        final long ident = Binder.clearCallingIdentity();
2170c593380d1bccbfbd45c404954b2670b65acc287fsatok                        try {
2171c593380d1bccbfbd45c404954b2670b65acc287fsatok                            buildInputMethodListLocked(mMethodList, mMethodMap);
2172c593380d1bccbfbd45c404954b2670b65acc287fsatok                        } finally {
2173c593380d1bccbfbd45c404954b2670b65acc287fsatok                            Binder.restoreCallingIdentity(ident);
2174c593380d1bccbfbd45c404954b2670b65acc287fsatok                        }
2175ee5e77cafec2eae70890abdcc1646ed39b06edddsatok                        return;
217691e88122cf28a48fd2e2260da7d3d87dd437227asatok                    }
217791e88122cf28a48fd2e2260da7d3d87dd437227asatok                }
217891e88122cf28a48fd2e2260da7d3d87dd437227asatok            }
2179e7c6998e0a953ae55487d4fe122739646f9280aasatok        }
2180ee5e77cafec2eae70890abdcc1646ed39b06edddsatok        return;
2181e7c6998e0a953ae55487d4fe122739646f9280aasatok    }
2182e7c6998e0a953ae55487d4fe122739646f9280aasatok
21832820351489537698ad153c6397edf3270455edc5satok    private void setInputMethodWithSubtypeId(IBinder token, String id, int subtypeId) {
21849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
21859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (token == null) {
21869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mContext.checkCallingOrSelfPermission(
21879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        android.Manifest.permission.WRITE_SECURE_SETTINGS)
21889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        != PackageManager.PERMISSION_GRANTED) {
21899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    throw new SecurityException(
21909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            "Using null token requires permission "
21919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            + android.Manifest.permission.WRITE_SECURE_SETTINGS);
21929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
21939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (mCurToken != token) {
2194cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
2195cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                        + " token: " + token);
21969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
21979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2199c593380d1bccbfbd45c404954b2670b65acc287fsatok            final long ident = Binder.clearCallingIdentity();
22009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
2201ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                setInputMethodLocked(id, subtypeId);
22029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
22039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Binder.restoreCallingIdentity(ident);
22049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
220842c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
22099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void hideMySoftInput(IBinder token, int flags) {
22104e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
22114e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
22124e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
22139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
22149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (token == null || mCurToken != token) {
2215cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                if (DEBUG) Slog.w(TAG, "Ignoring hideInputMethod of uid "
2216cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                        + Binder.getCallingUid() + " token: " + token);
22179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
22189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long ident = Binder.clearCallingIdentity();
22209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
22214df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                hideCurrentInputLocked(flags, null);
22224df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            } finally {
22234df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                Binder.restoreCallingIdentity(ident);
22244df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            }
22254df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        }
22264df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    }
2227ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
222842c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
22294df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    public void showMySoftInput(IBinder token, int flags) {
22304e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
22314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return;
22324e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
22334df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project        synchronized (mMethodMap) {
22344df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            if (token == null || mCurToken != token) {
2235cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                Slog.w(TAG, "Ignoring showMySoftInput of uid "
2236cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn                        + Binder.getCallingUid() + " token: " + token);
22374df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                return;
22384df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            }
22394df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            long ident = Binder.clearCallingIdentity();
22404df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project            try {
22414df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                showCurrentInputLocked(flags, null);
22429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
22439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Binder.restoreCallingIdentity(ident);
22449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void setEnabledSessionInMainThread(SessionState session) {
22499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnabledSession != session) {
22509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mEnabledSession != null) {
22519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
22528a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
22539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mEnabledSession.method.setSessionEnabled(
22549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mEnabledSession.session, false);
22559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
22569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
22579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEnabledSession = session;
22599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
22608a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
22619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                session.method.setSessionEnabled(
22629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        session.session, true);
22639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
22649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2267ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
226842c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
22699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean handleMessage(Message msg) {
2270758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov        SomeArgs args;
22719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (msg.what) {
22729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_SHOW_IM_PICKER:
22739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                showInputMethodMenu();
22749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
2275ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2276ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            case MSG_SHOW_IM_SUBTYPE_PICKER:
2277ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                showInputMethodSubtypeMenu();
2278ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                return true;
2279ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
228047a44916e2fb33cf4751906386d5f5c903b28d8bsatok            case MSG_SHOW_IM_SUBTYPE_ENABLER:
2281758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
22827fee71f66afef6421b92fa48e63d4bc73f5d0c27satok                showInputMethodAndSubtypeEnabler((String)args.arg1);
2283758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
2284217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                return true;
2285217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok
2286217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok            case MSG_SHOW_IM_CONFIG:
2287217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                showConfigureInputMethods();
228847a44916e2fb33cf4751906386d5f5c903b28d8bsatok                return true;
228947a44916e2fb33cf4751906386d5f5c903b28d8bsatok
22909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ---------------------------------------------------------
2291ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
22929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_UNBIND_INPUT:
22939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
22949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethod)msg.obj).unbindInput();
22959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
22969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // There is nothing interesting about the method dying.
22979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
22989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
22999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_BIND_INPUT:
2300758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
23019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethod)args.arg1).bindInput((InputBinding)args.arg2);
23039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2305758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
23069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
23079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_SHOW_SOFT_INPUT:
2308758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
23099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23104df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    ((IInputMethod)args.arg1).showSoftInput(msg.arg1,
23114df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            (ResultReceiver)args.arg2);
23129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2314758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
23159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
23169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_HIDE_SOFT_INPUT:
2317758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
23189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23194df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    ((IInputMethod)args.arg1).hideSoftInput(0,
23204df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            (ResultReceiver)args.arg2);
23219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2323758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
23249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
23259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_ATTACH_TOKEN:
2326758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
23279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23288a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    if (DEBUG) Slog.v(TAG, "Sending attach of token: " + args.arg2);
23299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethod)args.arg1).attachToken((IBinder)args.arg2);
23309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2332758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
23339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
23349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_CREATE_SESSION:
2335758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
23369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethod)args.arg1).createSession(
23389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (IInputMethodCallback)args.arg2);
23399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2341758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
23429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
23439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ---------------------------------------------------------
2344ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
23459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_START_INPUT:
2346758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
23479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SessionState session = (SessionState)args.arg1;
23499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setEnabledSessionInMainThread(session);
23509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    session.method.startInput((IInputContext)args.arg2,
23519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (EditorInfo)args.arg3);
23529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2354758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
23559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
23569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_RESTART_INPUT:
2357758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
23589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SessionState session = (SessionState)args.arg1;
23609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setEnabledSessionInMainThread(session);
23619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    session.method.restartInput((IInputContext)args.arg2,
23629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (EditorInfo)args.arg3);
23639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2365758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
23669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
2367ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
23689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ---------------------------------------------------------
2369ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
23709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_UNBIND_METHOD:
23719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1);
23739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // There is nothing interesting about the last client dying.
23759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
23769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
23779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_BIND_METHOD:
2378758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args = (SomeArgs)msg.obj;
23799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
23809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ((IInputMethodClient)args.arg1).onBindMethod(
23819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (InputBindResult)args.arg2);
23829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
23838a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.w(TAG, "Client died receiving input method " + args.arg2);
23849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2385758143ecfedbe08cc6c4fed0ad8ad7a854194ca4Svetoslav Ganov                args.recycle();
23869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
2387a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn            case MSG_SET_ACTIVE:
2388a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                try {
2389a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                    ((ClientState)msg.obj).client.setActive(msg.arg1 != 0);
2390a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                } catch (RemoteException e) {
2391a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                    Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
2392a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                            + ((ClientState)msg.obj).pid + " uid "
2393a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                            + ((ClientState)msg.obj).uid);
2394a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                }
2395a6e41342e2159402e33866e7145be357065d9c9aDianne Hackborn                return true;
239601038492ff0317f0d3cff54d8a7ee36bb31ff175satok
239701038492ff0317f0d3cff54d8a7ee36bb31ff175satok            // --------------------------------------------------------------
239801038492ff0317f0d3cff54d8a7ee36bb31ff175satok            case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
239901038492ff0317f0d3cff54d8a7ee36bb31ff175satok                mHardKeyboardListener.handleHardKeyboardStatusChange(
240001038492ff0317f0d3cff54d8a7ee36bb31ff175satok                        msg.arg1 == 1, msg.arg2 == 1);
240101038492ff0317f0d3cff54d8a7ee36bb31ff175satok                return true;
24029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
24049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
24059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24065b927c431f54ea47c3333afb7940d79e2e863f1asatok    private static boolean isSystemIme(InputMethodInfo inputMethod) {
24076da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        return (inputMethod.getServiceInfo().applicationInfo.flags
24086da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger                & ApplicationInfo.FLAG_SYSTEM) != 0;
24096da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger    }
24106da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
2411586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa    private static ArrayList<InputMethodSubtype> getSubtypes(InputMethodInfo imi) {
2412586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
2413586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        final int subtypeCount = imi.getSubtypeCount();
2414586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        for (int i = 0; i < subtypeCount; ++i) {
2415586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa            subtypes.add(imi.getSubtypeAt(i));
2416586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        }
2417586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa        return subtypes;
2418586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa    }
2419586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa
2420a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok    private static ArrayList<InputMethodSubtype> getOverridingImplicitlyEnabledSubtypes(
2421a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            InputMethodInfo imi, String mode) {
2422a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
2423a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        final int subtypeCount = imi.getSubtypeCount();
2424a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        for (int i = 0; i < subtypeCount; ++i) {
2425a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            final InputMethodSubtype subtype = imi.getSubtypeAt(i);
2426a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            if (subtype.overridesImplicitlyEnabledSubtype() && subtype.getMode().equals(mode)) {
2427a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                subtypes.add(subtype);
2428a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            }
2429a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        }
2430a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        return subtypes;
2431a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok    }
2432a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok
2433dc9ddaee9a710cf6f5d7f37350650f82e706c706satok    private InputMethodInfo getMostApplicableDefaultIMELocked() {
2434d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
24356da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        if (enabled != null && enabled.size() > 0) {
243683e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn            // We'd prefer to fall back on a system IME, since that is safer.
24370a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            int i = enabled.size();
24380a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            int firstFoundSystemIme = -1;
243983e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn            while (i > 0) {
244083e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn                i--;
2441dc9ddaee9a710cf6f5d7f37350650f82e706c706satok                final InputMethodInfo imi = enabled.get(i);
24420a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                if (isSystemImeThatHasEnglishSubtype(imi) && !imi.isAuxiliaryIme()) {
24430a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                    return imi;
24440a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                }
24450a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                if (firstFoundSystemIme < 0 && isSystemIme(imi) && !imi.isAuxiliaryIme()) {
24460a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                    firstFoundSystemIme = i;
244783e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn                }
244883e48f57e937a2e582707056f164aefa3c2f7e1dDianne Hackborn            }
24490a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            return enabled.get(Math.max(firstFoundSystemIme, 0));
2450dc9ddaee9a710cf6f5d7f37350650f82e706c706satok        }
2451dc9ddaee9a710cf6f5d7f37350650f82e706c706satok        return null;
2452dc9ddaee9a710cf6f5d7f37350650f82e706c706satok    }
2453dc9ddaee9a710cf6f5d7f37350650f82e706c706satok
2454dc9ddaee9a710cf6f5d7f37350650f82e706c706satok    private boolean chooseNewDefaultIMELocked() {
2455dc9ddaee9a710cf6f5d7f37350650f82e706c706satok        final InputMethodInfo imi = getMostApplicableDefaultIMELocked();
2456dc9ddaee9a710cf6f5d7f37350650f82e706c706satok        if (imi != null) {
245703eb319a3a7fe6fe9ab9eba6fc1f727285850906satok            if (DEBUG) {
245803eb319a3a7fe6fe9ab9eba6fc1f727285850906satok                Slog.d(TAG, "New default IME was selected: " + imi.getId());
245903eb319a3a7fe6fe9ab9eba6fc1f727285850906satok            }
2460723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            resetSelectedInputMethodAndSubtypeLocked(imi.getId());
24616da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger            return true;
24626da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        }
24636da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
24646da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        return false;
24656da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger    }
24666da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
24679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void buildInputMethodListLocked(ArrayList<InputMethodInfo> list,
24689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            HashMap<String, InputMethodInfo> map) {
24694e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (DEBUG) {
24704e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Slog.d(TAG, "--- re-buildInputMethodList " + ", \n ------ \n" + getStackTrace());
24714e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
24729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        list.clear();
24739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        map.clear();
2474ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
24754e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // Use for queryIntentServicesAsUser
24764e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final PackageManager pm = mContext.getPackageManager();
24777d3a5bcf300aea7bffb1d46f28e244ca807f5e82Dianne Hackborn        final Configuration config = mRes.getConfiguration();
2478e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani        final boolean haveHardKeyboard = config.keyboard == Configuration.KEYBOARD_QWERTY;
24794e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        String disabledSysImes = mSettings.getDisabledSystemInputMethods();
2480e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani        if (disabledSysImes == null) disabledSysImes = "";
24819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24824e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
24839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                new Intent(InputMethod.SERVICE_INTERFACE),
24844e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                PackageManager.GET_META_DATA, mSettings.getCurrentUserId());
2485ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2486e7c6998e0a953ae55487d4fe122739646f9280aasatok        final HashMap<String, List<InputMethodSubtype>> additionalSubtypes =
2487e7c6998e0a953ae55487d4fe122739646f9280aasatok                mFileManager.getAllAdditionalInputMethodSubtypes();
24889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < services.size(); ++i) {
24899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ResolveInfo ri = services.get(i);
24909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ServiceInfo si = ri.serviceInfo;
24919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ComponentName compName = new ComponentName(si.packageName, si.name);
24929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!android.Manifest.permission.BIND_INPUT_METHOD.equals(
24939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    si.permission)) {
24948a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Skipping input method " + compName
24959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + ": it does not require the permission "
24969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + android.Manifest.permission.BIND_INPUT_METHOD);
24979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
24989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
24999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25008a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (DEBUG) Slog.d(TAG, "Checking " + compName);
25019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
2503e7c6998e0a953ae55487d4fe122739646f9280aasatok                InputMethodInfo p = new InputMethodInfo(mContext, ri, additionalSubtypes);
25049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                list.add(p);
2505e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani                final String id = p.getId();
2506e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani                map.put(id, p);
25079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25085b927c431f54ea47c3333afb7940d79e2e863f1asatok                // Valid system default IMEs and IMEs that have English subtypes are enabled
250915451bd7afedb98a84574f69086936f883371c83Satoshi Kataoka                // by default
251015451bd7afedb98a84574f69086936f883371c83Satoshi Kataoka                if ((isValidSystemDefaultIme(p, mContext) || isSystemImeThatHasEnglishSubtype(p))) {
2511e861ec11c458b4f76eb80da518dfee6a400071bfAmith Yamasani                    setInputMethodEnabledLocked(id, true);
25126da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger                }
25136da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
25149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (DEBUG) {
25158a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.d(TAG, "Found a third-party input method " + p);
25169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2517ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
25189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (XmlPullParserException e) {
25198a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Unable to load input method " + compName, e);
25209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IOException e) {
25218a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Unable to load input method " + compName, e);
25229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25246da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger
25254e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final String defaultImiId = mSettings.getSelectedInputMethod();
25260a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok        if (!TextUtils.isEmpty(defaultImiId)) {
25270a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            if (!map.containsKey(defaultImiId)) {
25280a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                Slog.w(TAG, "Default IME is uninstalled. Choose new default IME.");
25290a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                if (chooseNewDefaultIMELocked()) {
25300a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                    updateFromSettingsLocked();
25310a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                }
25320a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            } else {
25330a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                // Double check that the default IME is certainly enabled.
25340a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok                setInputMethodEnabledLocked(defaultImiId, true);
25356da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger            }
25366da35a0c1205398b7df4776e359f7794584fb128Brandon Ballinger        }
25379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2538ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
25399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ----------------------------------------------------------------------
2540ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2541ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private void showInputMethodMenu() {
2542ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        showInputMethodMenuInternal(false);
2543ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
2544ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2545ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private void showInputMethodSubtypeMenu() {
2546ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        showInputMethodMenuInternal(true);
2547ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
2548ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2549217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok    private void showInputMethodAndSubtypeEnabler(String inputMethodId) {
2550f49688fa17b70313c0734f00df73bc3308a749e9Tadashi G. Takaoka        Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
255147a44916e2fb33cf4751906386d5f5c903b28d8bsatok        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
255286417ea3f8041481a085823a1aa9f66d747231e8satok                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
255386417ea3f8041481a085823a1aa9f66d747231e8satok                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
25547fee71f66afef6421b92fa48e63d4bc73f5d0c27satok        if (!TextUtils.isEmpty(inputMethodId)) {
25552548020c364c4119d134c84cc7a00ffca2dcbe7bTadashi G. Takaoka            intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
25567fee71f66afef6421b92fa48e63d4bc73f5d0c27satok        }
25573ba439d6481b7f23ade44bfde0700aaa1e076a32Satoshi Kataoka        mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
2558217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok    }
2559217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok
2560217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok    private void showConfigureInputMethods() {
2561217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok        Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
2562217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
2563217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
2564217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
25653ba439d6481b7f23ade44bfde0700aaa1e076a32Satoshi Kataoka        mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
256647a44916e2fb33cf4751906386d5f5c903b28d8bsatok    }
256747a44916e2fb33cf4751906386d5f5c903b28d8bsatok
25682c93efc9eb188532472edc9e0c3e1ab8121aa20dsatok    private boolean isScreenLocked() {
25692c93efc9eb188532472edc9e0c3e1ab8121aa20dsatok        return mKeyguardManager != null
25702c93efc9eb188532472edc9e0c3e1ab8121aa20dsatok                && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure();
25712c93efc9eb188532472edc9e0c3e1ab8121aa20dsatok    }
2572ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private void showInputMethodMenuInternal(boolean showSubtypes) {
25738a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        if (DEBUG) Slog.v(TAG, "Show switching menu");
25749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Context context = mContext;
25762c93efc9eb188532472edc9e0c3e1ab8121aa20dsatok        final boolean isScreenLocked = isScreenLocked();
2577ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
25784e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final String lastInputMethodId = mSettings.getSelectedInputMethod();
2579ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        int lastInputMethodSubtypeId = getSelectedInputMethodSubtypeId(lastInputMethodId);
25808a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
2581ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
25827f35c8cc88bea5230f001dd4356f864845d202e5satok        synchronized (mMethodMap) {
2583bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            final HashMap<InputMethodInfo, List<InputMethodSubtype>> immis =
2584bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                    getExplicitlyOrImplicitlyEnabledInputMethodsAndSubtypeListLocked();
25857f35c8cc88bea5230f001dd4356f864845d202e5satok            if (immis == null || immis.size() == 0) {
25867f35c8cc88bea5230f001dd4356f864845d202e5satok                return;
25877f35c8cc88bea5230f001dd4356f864845d202e5satok            }
2588ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
25898cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            hideInputMethodMenuLocked();
25909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2591688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            final List<ImeSubtypeListItem> imList =
2592688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    mImListManager.getSortedInputMethodAndSubtypeList(
2593688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            showSubtypes, mInputShown, isScreenLocked);
2594913a8925c07e854a80bf5df87561f290d3a56d61satok
2595c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok            if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
25964e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtypeLocked();
2597c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                if (currentSubtype != null) {
2598c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                    final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
2599c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                    lastInputMethodSubtypeId =
2600c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                            getSubtypeIdFromHashCode(currentImi, currentSubtype.hashCode());
2601c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                }
2602c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok            }
2603c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok
2604761eb3762f3602dd1859905ee4ba80f0ef6aec56Ken Wakasa            final int N = imList.size();
2605ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            mIms = new InputMethodInfo[N];
2606ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            mSubtypeIds = new int[N];
26078cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            int checkedItem = 0;
26088cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            for (int i = 0; i < N; ++i) {
260905dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                final ImeSubtypeListItem item = imList.get(i);
261005dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                mIms[i] = item.mImi;
261105dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                mSubtypeIds[i] = item.mSubtypeId;
26128cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                if (mIms[i].getId().equals(lastInputMethodId)) {
2613ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    int subtypeId = mSubtypeIds[i];
2614ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    if ((subtypeId == NOT_A_SUBTYPE_ID)
2615ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                            || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0)
2616ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                            || (subtypeId == lastInputMethodSubtypeId)) {
2617ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                        checkedItem = i;
2618ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                    }
26198cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                }
26209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
262105dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final TypedArray a = context.obtainStyledAttributes(null,
26228cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    com.android.internal.R.styleable.DialogPreference,
26238cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    com.android.internal.R.attr.alertDialogStyle, 0);
26248cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            mDialogBuilder = new AlertDialog.Builder(context)
26258cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    .setOnCancelListener(new OnCancelListener() {
262642c5a1666c4e576ccd5974233513100aad2c1534satok                        @Override
26278cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                        public void onCancel(DialogInterface dialog) {
26289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            hideInputMethodMenu();
26298cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                        }
26308cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    })
26318cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    .setIcon(a.getDrawable(
26328cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                            com.android.internal.R.styleable.DialogPreference_dialogTitle));
26338cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn            a.recycle();
263401038492ff0317f0d3cff54d8a7ee36bb31ff175satok            final LayoutInflater inflater =
263501038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
263601038492ff0317f0d3cff54d8a7ee36bb31ff175satok            final View tv = inflater.inflate(
263701038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    com.android.internal.R.layout.input_method_switch_dialog_title, null);
263801038492ff0317f0d3cff54d8a7ee36bb31ff175satok            mDialogBuilder.setCustomTitle(tv);
263901038492ff0317f0d3cff54d8a7ee36bb31ff175satok
264001038492ff0317f0d3cff54d8a7ee36bb31ff175satok            // Setup layout for a toggle switch of the hardware keyboard
264101038492ff0317f0d3cff54d8a7ee36bb31ff175satok            mSwitchingDialogTitleView = tv;
264201038492ff0317f0d3cff54d8a7ee36bb31ff175satok            mSwitchingDialogTitleView.findViewById(
264301038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    com.android.internal.R.id.hard_keyboard_section).setVisibility(
264401038492ff0317f0d3cff54d8a7ee36bb31ff175satok                            mWindowManagerService.isHardKeyboardAvailable() ?
264501038492ff0317f0d3cff54d8a7ee36bb31ff175satok                                    View.VISIBLE : View.GONE);
264601038492ff0317f0d3cff54d8a7ee36bb31ff175satok            final Switch hardKeySwitch =  ((Switch)mSwitchingDialogTitleView.findViewById(
264701038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    com.android.internal.R.id.hard_keyboard_switch));
264801038492ff0317f0d3cff54d8a7ee36bb31ff175satok            hardKeySwitch.setChecked(mWindowManagerService.isHardKeyboardEnabled());
264901038492ff0317f0d3cff54d8a7ee36bb31ff175satok            hardKeySwitch.setOnCheckedChangeListener(
265001038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    new OnCheckedChangeListener() {
265101038492ff0317f0d3cff54d8a7ee36bb31ff175satok                        @Override
265201038492ff0317f0d3cff54d8a7ee36bb31ff175satok                        public void onCheckedChanged(
265301038492ff0317f0d3cff54d8a7ee36bb31ff175satok                                CompoundButton buttonView, boolean isChecked) {
265401038492ff0317f0d3cff54d8a7ee36bb31ff175satok                            mWindowManagerService.setHardKeyboardEnabled(isChecked);
265501038492ff0317f0d3cff54d8a7ee36bb31ff175satok                        }
265601038492ff0317f0d3cff54d8a7ee36bb31ff175satok                    });
2657d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
265805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(context,
265905dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                    com.android.internal.R.layout.simple_list_item_2_single_choice, imList,
266005dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                    checkedItem);
266105dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa
266205dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mDialogBuilder.setSingleChoiceItems(adapter, checkedItem,
26638cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    new AlertDialog.OnClickListener() {
266442c5a1666c4e576ccd5974233513100aad2c1534satok                        @Override
26658cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                        public void onClick(DialogInterface dialog, int which) {
26668cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                            synchronized (mMethodMap) {
2667ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                if (mIms == null || mIms.length <= which
2668ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                        || mSubtypeIds == null || mSubtypeIds.length <= which) {
26698cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                    return;
26708cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                }
26718cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                InputMethodInfo im = mIms[which];
2672ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                int subtypeId = mSubtypeIds[which];
26738cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                hideInputMethodMenu();
26748cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                if (im != null) {
2675ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                    if ((subtypeId < 0)
2676586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                                            || (subtypeId >= im.getSubtypeCount())) {
2677ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                        subtypeId = NOT_A_SUBTYPE_ID;
2678ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                    }
2679ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                                    setInputMethodLocked(im.getId(), subtypeId);
26808cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                                }
268120cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn                            }
26829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
26838cf1bcd1d26ddbb471e4968b70e32ecabe4f7a20Dianne Hackborn                    });
26849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2685bc81b692d51a9cd6f9d61584aacd8308ac3366easatok            if (showSubtypes && !isScreenLocked) {
268682beadfa067b1e286fa604f8d7960d769411c954satok                mDialogBuilder.setPositiveButton(
268782beadfa067b1e286fa604f8d7960d769411c954satok                        com.android.internal.R.string.configure_input_methods,
26887f35c8cc88bea5230f001dd4356f864845d202e5satok                        new DialogInterface.OnClickListener() {
268942c5a1666c4e576ccd5974233513100aad2c1534satok                            @Override
26907f35c8cc88bea5230f001dd4356f864845d202e5satok                            public void onClick(DialogInterface dialog, int whichButton) {
2691217f548e79ab1ac3dd9e5be8fb6feaa6dcbe4000satok                                showConfigureInputMethods();
26927f35c8cc88bea5230f001dd4356f864845d202e5satok                            }
26937f35c8cc88bea5230f001dd4356f864845d202e5satok                        });
26947f35c8cc88bea5230f001dd4356f864845d202e5satok            }
26959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSwitchingDialog = mDialogBuilder.create();
2696e3a7f628c6d9fef42be24999b3137ebe5c6f3525Dianne Hackborn            mSwitchingDialog.setCanceledOnTouchOutside(true);
26979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSwitchingDialog.getWindow().setType(
26989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
2699c86884cd839123e3be3cc97c8f293ac47d3624a9Satoshi Kataoka            mSwitchingDialog.getWindow().getAttributes().privateFlags |=
2700c86884cd839123e3be3cc97c8f293ac47d3624a9Satoshi Kataoka                    WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
2701e3a7f628c6d9fef42be24999b3137ebe5c6f3525Dianne Hackborn            mSwitchingDialog.getWindow().getAttributes().setTitle("Select input method");
27029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSwitchingDialog.show();
27039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2705ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
270693d744deb167d5c681b5bb5627fd36a92f1ea79asatok    private static class ImeSubtypeListItem implements Comparable<ImeSubtypeListItem> {
270705dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        public final CharSequence mImeName;
270805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        public final CharSequence mSubtypeName;
270905dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        public final InputMethodInfo mImi;
271005dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        public final int mSubtypeId;
271193d744deb167d5c681b5bb5627fd36a92f1ea79asatok        private final boolean mIsSystemLocale;
271293d744deb167d5c681b5bb5627fd36a92f1ea79asatok        private final boolean mIsSystemLanguage;
271393d744deb167d5c681b5bb5627fd36a92f1ea79asatok
271405dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        public ImeSubtypeListItem(CharSequence imeName, CharSequence subtypeName,
271593d744deb167d5c681b5bb5627fd36a92f1ea79asatok                InputMethodInfo imi, int subtypeId, String subtypeLocale, String systemLocale) {
271605dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mImeName = imeName;
271705dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mSubtypeName = subtypeName;
271805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mImi = imi;
271905dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mSubtypeId = subtypeId;
272093d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (TextUtils.isEmpty(subtypeLocale)) {
272193d744deb167d5c681b5bb5627fd36a92f1ea79asatok                mIsSystemLocale = false;
272293d744deb167d5c681b5bb5627fd36a92f1ea79asatok                mIsSystemLanguage = false;
272393d744deb167d5c681b5bb5627fd36a92f1ea79asatok            } else {
272493d744deb167d5c681b5bb5627fd36a92f1ea79asatok                mIsSystemLocale = subtypeLocale.equals(systemLocale);
272593d744deb167d5c681b5bb5627fd36a92f1ea79asatok                mIsSystemLanguage = mIsSystemLocale
272693d744deb167d5c681b5bb5627fd36a92f1ea79asatok                        || subtypeLocale.startsWith(systemLocale.substring(0, 2));
272793d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
272893d744deb167d5c681b5bb5627fd36a92f1ea79asatok        }
272993d744deb167d5c681b5bb5627fd36a92f1ea79asatok
273093d744deb167d5c681b5bb5627fd36a92f1ea79asatok        @Override
273193d744deb167d5c681b5bb5627fd36a92f1ea79asatok        public int compareTo(ImeSubtypeListItem other) {
273293d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (TextUtils.isEmpty(mImeName)) {
273393d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return 1;
273493d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
273593d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (TextUtils.isEmpty(other.mImeName)) {
273693d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return -1;
273793d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
273893d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (!TextUtils.equals(mImeName, other.mImeName)) {
273993d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return mImeName.toString().compareTo(other.mImeName.toString());
274093d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
274193d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (TextUtils.equals(mSubtypeName, other.mSubtypeName)) {
274293d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return 0;
274393d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
274493d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (mIsSystemLocale) {
274593d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return -1;
274693d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
274793d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (other.mIsSystemLocale) {
274893d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return 1;
274993d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
275093d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (mIsSystemLanguage) {
275193d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return -1;
275293d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
275393d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (other.mIsSystemLanguage) {
275493d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return 1;
275593d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
275693d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (TextUtils.isEmpty(mSubtypeName)) {
275793d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return 1;
275893d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
275993d744deb167d5c681b5bb5627fd36a92f1ea79asatok            if (TextUtils.isEmpty(other.mSubtypeName)) {
276093d744deb167d5c681b5bb5627fd36a92f1ea79asatok                return -1;
276193d744deb167d5c681b5bb5627fd36a92f1ea79asatok            }
276293d744deb167d5c681b5bb5627fd36a92f1ea79asatok            return mSubtypeName.toString().compareTo(other.mSubtypeName.toString());
276305dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        }
276405dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa    }
276505dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa
276605dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa    private static class ImeSubtypeListAdapter extends ArrayAdapter<ImeSubtypeListItem> {
276705dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        private final LayoutInflater mInflater;
276805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        private final int mTextViewResourceId;
276905dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        private final List<ImeSubtypeListItem> mItemsList;
277005dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        private final int mCheckedItem;
277105dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        public ImeSubtypeListAdapter(Context context, int textViewResourceId,
277205dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                List<ImeSubtypeListItem> itemsList, int checkedItem) {
277305dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            super(context, textViewResourceId, itemsList);
277405dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mTextViewResourceId = textViewResourceId;
277505dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mItemsList = itemsList;
277605dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mCheckedItem = checkedItem;
277705dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
277805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        }
277905dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa
278005dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        @Override
278105dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        public View getView(int position, View convertView, ViewGroup parent) {
278205dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final View view = convertView != null ? convertView
278305dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                    : mInflater.inflate(mTextViewResourceId, null);
278405dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            if (position < 0 || position >= mItemsList.size()) return view;
278505dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final ImeSubtypeListItem item = mItemsList.get(position);
278605dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final CharSequence imeName = item.mImeName;
278705dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final CharSequence subtypeName = item.mSubtypeName;
278805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final TextView firstTextView = (TextView)view.findViewById(android.R.id.text1);
278905dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final TextView secondTextView = (TextView)view.findViewById(android.R.id.text2);
279005dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            if (TextUtils.isEmpty(subtypeName)) {
279105dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                firstTextView.setText(imeName);
279205dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                secondTextView.setVisibility(View.GONE);
279305dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            } else {
279405dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                firstTextView.setText(subtypeName);
279505dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                secondTextView.setText(imeName);
279605dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                secondTextView.setVisibility(View.VISIBLE);
279705dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            }
279805dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            final RadioButton radioButton =
279905dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa                    (RadioButton)view.findViewById(com.android.internal.R.id.radio);
280005dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            radioButton.setChecked(position == mCheckedItem);
280105dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa            return view;
280205dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa        }
280305dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa    }
280405dbb65dfa3b81a4b70069ca6aa0a343b56565f9Ken Wakasa
28059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void hideInputMethodMenu() {
2806105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        synchronized (mMethodMap) {
2807105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            hideInputMethodMenuLocked();
2808105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
2809105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
2810ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2811105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    void hideInputMethodMenuLocked() {
28128a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        if (DEBUG) Slog.v(TAG, "Hide switching menu");
28139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2814105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (mSwitchingDialog != null) {
2815105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mSwitchingDialog.dismiss();
2816105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mSwitchingDialog = null;
28179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2818ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2819105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mDialogBuilder = null;
2820105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mIms = null;
28219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2822ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
28239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ----------------------------------------------------------------------
2824ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
282542c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
28269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean setInputMethodEnabled(String id, boolean enabled) {
28274e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // TODO: Make this work even for non-current users?
28284e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
28294e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
28304e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
28319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
28329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mContext.checkCallingOrSelfPermission(
28339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    android.Manifest.permission.WRITE_SECURE_SETTINGS)
28349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    != PackageManager.PERMISSION_GRANTED) {
28359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new SecurityException(
28369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "Requires permission "
28379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + android.Manifest.permission.WRITE_SECURE_SETTINGS);
28389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
283921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
28409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long ident = Binder.clearCallingIdentity();
28419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
284221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                return setInputMethodEnabledLocked(id, enabled);
284321f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            } finally {
284421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn                Binder.restoreCallingIdentity(ident);
284521f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            }
284621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        }
284721f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    }
284821f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn
284921f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn    boolean setInputMethodEnabledLocked(String id, boolean enabled) {
285021f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        // Make sure this is a valid input method.
285121f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        InputMethodInfo imm = mMethodMap.get(id);
285221f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        if (imm == null) {
2853d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
285421f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn        }
2855ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2856d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
2857d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                .getEnabledInputMethodsAndSubtypeListLocked();
2858ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
2859d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        if (enabled) {
2860d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
2861d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                if (pair.first.equals(id)) {
2862d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // We are enabling this input method, but it is already enabled.
2863d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // Nothing to do. The previous state was enabled.
2864d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    return true;
28659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
286621f1bd17b2dfe361acbb28453b3f3b1a110932faDianne Hackborn            }
2867d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mSettings.appendAndPutEnabledInputMethodLocked(id, false);
2868d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            // Previous state was disabled.
2869d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return false;
2870d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        } else {
2871d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            StringBuilder builder = new StringBuilder();
2872d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (mSettings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
2873d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    builder, enabledInputMethodsList, id)) {
2874d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Disabled input method is currently selected, switch to another one.
28754e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                final String selId = mSettings.getSelectedInputMethod();
287603eb319a3a7fe6fe9ab9eba6fc1f727285850906satok                if (id.equals(selId) && !chooseNewDefaultIMELocked()) {
287703eb319a3a7fe6fe9ab9eba6fc1f727285850906satok                    Slog.i(TAG, "Can't find new IME, unsetting the current input method.");
287803eb319a3a7fe6fe9ab9eba6fc1f727285850906satok                    resetSelectedInputMethodAndSubtypeLocked("");
2879d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
2880d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Previous state was enabled.
2881d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                return true;
2882d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            } else {
2883d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // We are disabling the input method but it is already disabled.
2884d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Nothing to do.  The previous state was disabled.
28859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
28869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28894df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project
289057ffc00239edcfe733832771e1429fca20182207satok    private boolean canAddToLastInputMethod(InputMethodSubtype subtype) {
289157ffc00239edcfe733832771e1429fca20182207satok        if (subtype == null) return true;
28929b4157935af9e44571187a9533c2cc9b413383bfsatok        return !subtype.isAuxiliary();
289357ffc00239edcfe733832771e1429fca20182207satok    }
289457ffc00239edcfe733832771e1429fca20182207satok
2895723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    private void saveCurrentInputMethodAndSubtypeToHistory() {
2896723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        String subtypeId = NOT_A_SUBTYPE_ID_STR;
2897723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        if (mCurrentSubtype != null) {
2898723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            subtypeId = String.valueOf(mCurrentSubtype.hashCode());
2899723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
290057ffc00239edcfe733832771e1429fca20182207satok        if (canAddToLastInputMethod(mCurrentSubtype)) {
290157ffc00239edcfe733832771e1429fca20182207satok            mSettings.addSubtypeToHistory(mCurMethodId, subtypeId);
290257ffc00239edcfe733832771e1429fca20182207satok        }
2903ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
2904ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2905723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
2906723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            boolean setSubtypeOnly) {
2907723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        // Update the history of InputMethod and Subtype
2908723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        saveCurrentInputMethodAndSubtypeToHistory();
2909723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2910723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        // Set Subtype here
2911723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        if (imi == null || subtypeId < 0) {
2912723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
29130ba75bb22c2992f649ee5f7605a2b45442ad4862Tadashi G. Takaoka            mCurrentSubtype = null;
2914723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        } else {
2915586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa            if (subtypeId < imi.getSubtypeCount()) {
2916586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                InputMethodSubtype subtype = imi.getSubtypeAt(subtypeId);
2917586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                mSettings.putSelectedSubtype(subtype.hashCode());
2918586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                mCurrentSubtype = subtype;
2919723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            } else {
2920723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
2921d81e950265356c81276b73da68a535ffa48d72f0satok                // If the subtype is not specified, choose the most applicable one
29224e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                mCurrentSubtype = getCurrentInputMethodSubtypeLocked();
2923723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2924723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2925723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
29264c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // Workaround.
29274c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // ASEC is not ready in the IMMS constructor. Accordingly, forward-locked
29284c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // IMEs are not recognized and considered uninstalled.
29294c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // Actually, we can't move everything after SystemReady because
29304c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // IMMS needs to run in the encryption lock screen. So, we just skip changing
29314c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // the default IME here and try cheking the default IME again in systemReady().
29324c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // TODO: Do nothing before system ready and implement a separated logic for
29334c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // the encryption lock screen.
29344c0e7152e74d091eb78af8baacd38287ba95a1a1satok        // TODO: ASEC should be ready before IMMS is instantiated.
29354c0e7152e74d091eb78af8baacd38287ba95a1a1satok        if (mSystemReady && !setSubtypeOnly) {
2936723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // Set InputMethod here
2937723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mSettings.putSelectedInputMethod(imi != null ? imi.getId() : "");
29381ab852fbcfe155c9d4373b7130f8515591669634satok        }
2939ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
2940ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2941723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
2942723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        InputMethodInfo imi = mMethodMap.get(newDefaultIme);
2943723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        int lastSubtypeId = NOT_A_SUBTYPE_ID;
2944723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        // newDefaultIme is empty when there is no candidate for the selected IME.
2945723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        if (imi != null && !TextUtils.isEmpty(newDefaultIme)) {
2946723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            String subtypeHashCode = mSettings.getLastSubtypeForInputMethodLocked(newDefaultIme);
2947723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (subtypeHashCode != null) {
2948723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                try {
2949723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    lastSubtypeId = getSubtypeIdFromHashCode(
2950723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                            imi, Integer.valueOf(subtypeHashCode));
2951723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                } catch (NumberFormatException e) {
2952723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    Slog.w(TAG, "HashCode for subtype looks broken: " + subtypeHashCode, e);
2953723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
2954723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
2955723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
2956723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        setSelectedInputMethodAndSubtypeLocked(imi, lastSubtypeId, false);
2957723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    }
2958723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2959ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private int getSelectedInputMethodSubtypeId(String id) {
2960ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        InputMethodInfo imi = mMethodMap.get(id);
2961ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        if (imi == null) {
2962ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            return NOT_A_SUBTYPE_ID;
2963ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        }
29644e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final int subtypeHashCode = mSettings.getSelectedInputMethodSubtypeHashCode();
29654e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        return getSubtypeIdFromHashCode(imi, subtypeHashCode);
2966723a27ef3d7c94fc666abc52e0abd5e8526acb69satok    }
2967723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
2968fdf419e81d795593e3792c9e78f33ed899ff098esatok    private static boolean isValidSubtypeId(InputMethodInfo imi, int subtypeHashCode) {
2969fdf419e81d795593e3792c9e78f33ed899ff098esatok        return getSubtypeIdFromHashCode(imi, subtypeHashCode) != NOT_A_SUBTYPE_ID;
2970fdf419e81d795593e3792c9e78f33ed899ff098esatok    }
2971fdf419e81d795593e3792c9e78f33ed899ff098esatok
2972fdf419e81d795593e3792c9e78f33ed899ff098esatok    private static int getSubtypeIdFromHashCode(InputMethodInfo imi, int subtypeHashCode) {
29732820351489537698ad153c6397edf3270455edc5satok        if (imi != null) {
2974586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa            final int subtypeCount = imi.getSubtypeCount();
2975586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa            for (int i = 0; i < subtypeCount; ++i) {
2976586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                InputMethodSubtype ims = imi.getSubtypeAt(i);
29772820351489537698ad153c6397edf3270455edc5satok                if (subtypeHashCode == ims.hashCode()) {
29782820351489537698ad153c6397edf3270455edc5satok                    return i;
29792820351489537698ad153c6397edf3270455edc5satok                }
2980ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            }
2981ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        }
2982ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        return NOT_A_SUBTYPE_ID;
2983ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
2984ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2985a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok    private static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
2986a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            Resources res, InputMethodInfo imi) {
2987a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        final List<InputMethodSubtype> subtypes = getSubtypes(imi);
2988df31ae6a3011d47421a6ac10021f9649dc34a156satok        final String systemLocale = res.getConfiguration().locale.toString();
29893da922367c0dbe67b97fe97fcfca13fd93602f7asatok        if (TextUtils.isEmpty(systemLocale)) return new ArrayList<InputMethodSubtype>();
29904a553e3a70d26fac5d7b7ec1142e0cabfdd66670satok        final HashMap<String, InputMethodSubtype> applicableModeAndSubtypesMap =
29913da922367c0dbe67b97fe97fcfca13fd93602f7asatok                new HashMap<String, InputMethodSubtype>();
299216331c8a1d33defccc5cbb18694def79196c921bsatok        final int N = subtypes.size();
299316331c8a1d33defccc5cbb18694def79196c921bsatok        for (int i = 0; i < N; ++i) {
2994a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            // scan overriding implicitly enabled subtypes.
2995a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            InputMethodSubtype subtype = subtypes.get(i);
2996a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            if (subtype.overridesImplicitlyEnabledSubtype()) {
2997a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                final String mode = subtype.getMode();
2998a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                if (!applicableModeAndSubtypesMap.containsKey(mode)) {
2999a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                    applicableModeAndSubtypesMap.put(mode, subtype);
3000a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                }
3001a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            }
3002a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        }
3003a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        if (applicableModeAndSubtypesMap.size() > 0) {
3004a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            return new ArrayList<InputMethodSubtype>(applicableModeAndSubtypesMap.values());
3005a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        }
3006a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        for (int i = 0; i < N; ++i) {
30074a553e3a70d26fac5d7b7ec1142e0cabfdd66670satok            final InputMethodSubtype subtype = subtypes.get(i);
30083da922367c0dbe67b97fe97fcfca13fd93602f7asatok            final String locale = subtype.getLocale();
30093da922367c0dbe67b97fe97fcfca13fd93602f7asatok            final String mode = subtype.getMode();
30103da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // When system locale starts with subtype's locale, that subtype will be applicable
30113da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // for system locale
30123da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // For instance, it's clearly applicable for cases like system locale = en_US and
30133da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // subtype = en, but it is not necessarily considered applicable for cases like system
30143da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // locale = en and subtype = en_US.
30153da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // We just call systemLocale.startsWith(locale) in this function because there is no
30163da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // need to find applicable subtypes aggressively unlike
30173da922367c0dbe67b97fe97fcfca13fd93602f7asatok            // findLastResortApplicableSubtypeLocked.
30183da922367c0dbe67b97fe97fcfca13fd93602f7asatok            if (systemLocale.startsWith(locale)) {
30194a553e3a70d26fac5d7b7ec1142e0cabfdd66670satok                final InputMethodSubtype applicableSubtype = applicableModeAndSubtypesMap.get(mode);
30203da922367c0dbe67b97fe97fcfca13fd93602f7asatok                // If more applicable subtypes are contained, skip.
30214a553e3a70d26fac5d7b7ec1142e0cabfdd66670satok                if (applicableSubtype != null) {
30224a553e3a70d26fac5d7b7ec1142e0cabfdd66670satok                    if (systemLocale.equals(applicableSubtype.getLocale())) continue;
30234a553e3a70d26fac5d7b7ec1142e0cabfdd66670satok                    if (!systemLocale.equals(locale)) continue;
30244a553e3a70d26fac5d7b7ec1142e0cabfdd66670satok                }
30253da922367c0dbe67b97fe97fcfca13fd93602f7asatok                applicableModeAndSubtypesMap.put(mode, subtype);
302616331c8a1d33defccc5cbb18694def79196c921bsatok            }
302716331c8a1d33defccc5cbb18694def79196c921bsatok        }
3028c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok        final InputMethodSubtype keyboardSubtype
3029c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                = applicableModeAndSubtypesMap.get(SUBTYPE_MODE_KEYBOARD);
30304a28bde70e23b2ed151d52690da702da7f23cf5esatok        final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<InputMethodSubtype>(
30313da922367c0dbe67b97fe97fcfca13fd93602f7asatok                applicableModeAndSubtypesMap.values());
3032c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok        if (keyboardSubtype != null && !keyboardSubtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) {
3033c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok            for (int i = 0; i < N; ++i) {
3034c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                final InputMethodSubtype subtype = subtypes.get(i);
3035c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                final String mode = subtype.getMode();
3036c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                if (SUBTYPE_MODE_KEYBOARD.equals(mode) && subtype.containsExtraValueKey(
3037c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                        TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)) {
3038c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                    applicableSubtypes.add(subtype);
3039c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok                }
3040c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok            }
3041c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok        }
3042c36905673a7bcafe9ec74e82e6c4977f2aca6a50satok        if (keyboardSubtype == null) {
304316331c8a1d33defccc5cbb18694def79196c921bsatok            InputMethodSubtype lastResortKeyboardSubtype = findLastResortApplicableSubtypeLocked(
3044df31ae6a3011d47421a6ac10021f9649dc34a156satok                    res, subtypes, SUBTYPE_MODE_KEYBOARD, systemLocale, true);
304516331c8a1d33defccc5cbb18694def79196c921bsatok            if (lastResortKeyboardSubtype != null) {
304616331c8a1d33defccc5cbb18694def79196c921bsatok                applicableSubtypes.add(lastResortKeyboardSubtype);
304716331c8a1d33defccc5cbb18694def79196c921bsatok            }
304816331c8a1d33defccc5cbb18694def79196c921bsatok        }
304916331c8a1d33defccc5cbb18694def79196c921bsatok        return applicableSubtypes;
305016331c8a1d33defccc5cbb18694def79196c921bsatok    }
305116331c8a1d33defccc5cbb18694def79196c921bsatok
30524e4569dab5c75804b01a19b2d6e6101b445c1c68satok    /**
30534e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * If there are no selected subtypes, tries finding the most applicable one according to the
30544e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * given locale.
30554e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * @param subtypes this function will search the most applicable subtype in subtypes
30564e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * @param mode subtypes will be filtered by mode
30574e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * @param locale subtypes will be filtered by locale
30587599a7fb1ab5b75ca801f7d7e448f4c097320e01satok     * @param canIgnoreLocaleAsLastResort if this function can't find the most applicable subtype,
30597599a7fb1ab5b75ca801f7d7e448f4c097320e01satok     * it will return the first subtype matched with mode
30604e4569dab5c75804b01a19b2d6e6101b445c1c68satok     * @return the most applicable subtypeId
30614e4569dab5c75804b01a19b2d6e6101b445c1c68satok     */
3062df31ae6a3011d47421a6ac10021f9649dc34a156satok    private static InputMethodSubtype findLastResortApplicableSubtypeLocked(
3063df31ae6a3011d47421a6ac10021f9649dc34a156satok            Resources res, List<InputMethodSubtype> subtypes, String mode, String locale,
30647599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            boolean canIgnoreLocaleAsLastResort) {
30658fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        if (subtypes == null || subtypes.size() == 0) {
3066cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            return null;
30678fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        }
30684e4569dab5c75804b01a19b2d6e6101b445c1c68satok        if (TextUtils.isEmpty(locale)) {
3069df31ae6a3011d47421a6ac10021f9649dc34a156satok            locale = res.getConfiguration().locale.toString();
30704e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
30718fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        final String language = locale.substring(0, 2);
30728fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        boolean partialMatchFound = false;
3073cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok        InputMethodSubtype applicableSubtype = null;
30747599a7fb1ab5b75ca801f7d7e448f4c097320e01satok        InputMethodSubtype firstMatchedModeSubtype = null;
307516331c8a1d33defccc5cbb18694def79196c921bsatok        final int N = subtypes.size();
307616331c8a1d33defccc5cbb18694def79196c921bsatok        for (int i = 0; i < N; ++i) {
3077cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            InputMethodSubtype subtype = subtypes.get(i);
3078cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            final String subtypeLocale = subtype.getLocale();
3079d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok            // An applicable subtype should match "mode". If mode is null, mode will be ignored,
3080d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok            // and all subtypes with all modes can be candidates.
3081d871343dbbde38f25ac0b41155e2f9d2dd7aadcasatok            if (mode == null || subtypes.get(i).getMode().equalsIgnoreCase(mode)) {
30827599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                if (firstMatchedModeSubtype == null) {
30837599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                    firstMatchedModeSubtype = subtype;
30847599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                }
30859ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                if (locale.equals(subtypeLocale)) {
30869ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                    // Exact match (e.g. system locale is "en_US" and subtype locale is "en_US")
3087cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    applicableSubtype = subtype;
30889ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                    break;
30899ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                } else if (!partialMatchFound && subtypeLocale.startsWith(language)) {
30909ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                    // Partial match (e.g. system locale is "en_US" and subtype locale is "en")
3091cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    applicableSubtype = subtype;
30929ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                    partialMatchFound = true;
30939ef0283bdcd9534cc09ae37eb2b78771b95247b5satok                }
30948fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok            }
30958fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        }
30968fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok
30977599a7fb1ab5b75ca801f7d7e448f4c097320e01satok        if (applicableSubtype == null && canIgnoreLocaleAsLastResort) {
30987599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            return firstMatchedModeSubtype;
309916331c8a1d33defccc5cbb18694def79196c921bsatok        }
310016331c8a1d33defccc5cbb18694def79196c921bsatok
31018fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        // The first subtype applicable to the system locale will be defined as the most applicable
31028fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        // subtype.
31038fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        if (DEBUG) {
310416331c8a1d33defccc5cbb18694def79196c921bsatok            if (applicableSubtype != null) {
310516331c8a1d33defccc5cbb18694def79196c921bsatok                Slog.d(TAG, "Applicable InputMethodSubtype was found: "
310616331c8a1d33defccc5cbb18694def79196c921bsatok                        + applicableSubtype.getMode() + "," + applicableSubtype.getLocale());
310716331c8a1d33defccc5cbb18694def79196c921bsatok            }
31088fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        }
3109cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok        return applicableSubtype;
31108fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok    }
31118fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok
31124e4569dab5c75804b01a19b2d6e6101b445c1c68satok    // If there are no selected shortcuts, tries finding the most applicable ones.
31134e4569dab5c75804b01a19b2d6e6101b445c1c68satok    private Pair<InputMethodInfo, InputMethodSubtype>
31144e4569dab5c75804b01a19b2d6e6101b445c1c68satok            findLastResortApplicableShortcutInputMethodAndSubtypeLocked(String mode) {
31154e4569dab5c75804b01a19b2d6e6101b445c1c68satok        List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
31164e4569dab5c75804b01a19b2d6e6101b445c1c68satok        InputMethodInfo mostApplicableIMI = null;
3117cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok        InputMethodSubtype mostApplicableSubtype = null;
31184e4569dab5c75804b01a19b2d6e6101b445c1c68satok        boolean foundInSystemIME = false;
31194e4569dab5c75804b01a19b2d6e6101b445c1c68satok
31204e4569dab5c75804b01a19b2d6e6101b445c1c68satok        // Search applicable subtype for each InputMethodInfo
31214e4569dab5c75804b01a19b2d6e6101b445c1c68satok        for (InputMethodInfo imi: imis) {
31227599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            final String imiId = imi.getId();
31237599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            if (foundInSystemIME && !imiId.equals(mCurMethodId)) {
31247599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                continue;
31257599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            }
3126cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            InputMethodSubtype subtype = null;
3127df31ae6a3011d47421a6ac10021f9649dc34a156satok            final List<InputMethodSubtype> enabledSubtypes =
31284e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    getEnabledInputMethodSubtypeListLocked(imi, true);
3129df31ae6a3011d47421a6ac10021f9649dc34a156satok            // 1. Search by the current subtype's locale from enabledSubtypes.
31304e4569dab5c75804b01a19b2d6e6101b445c1c68satok            if (mCurrentSubtype != null) {
3131cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                subtype = findLastResortApplicableSubtypeLocked(
3132df31ae6a3011d47421a6ac10021f9649dc34a156satok                        mRes, enabledSubtypes, mode, mCurrentSubtype.getLocale(), false);
31334e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
3134df31ae6a3011d47421a6ac10021f9649dc34a156satok            // 2. Search by the system locale from enabledSubtypes.
3135df31ae6a3011d47421a6ac10021f9649dc34a156satok            // 3. Search the first enabled subtype matched with mode from enabledSubtypes.
3136cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            if (subtype == null) {
3137cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                subtype = findLastResortApplicableSubtypeLocked(
3138df31ae6a3011d47421a6ac10021f9649dc34a156satok                        mRes, enabledSubtypes, mode, null, true);
31397599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            }
3140a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            final ArrayList<InputMethodSubtype> overridingImplicitlyEnabledSubtypes =
3141a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                    getOverridingImplicitlyEnabledSubtypes(imi, mode);
3142a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            final ArrayList<InputMethodSubtype> subtypesForSearch =
3143a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                    overridingImplicitlyEnabledSubtypes.isEmpty()
3144a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                            ? getSubtypes(imi) : overridingImplicitlyEnabledSubtypes;
31457599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            // 4. Search by the current subtype's locale from all subtypes.
31467599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            if (subtype == null && mCurrentSubtype != null) {
31477599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                subtype = findLastResortApplicableSubtypeLocked(
3148a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                        mRes, subtypesForSearch, mode, mCurrentSubtype.getLocale(), false);
31494e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
31507599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            // 5. Search by the system locale from all subtypes.
31517599a7fb1ab5b75ca801f7d7e448f4c097320e01satok            // 6. Search the first enabled subtype matched with mode from all subtypes.
3152cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            if (subtype == null) {
31537599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                subtype = findLastResortApplicableSubtypeLocked(
3154a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                        mRes, subtypesForSearch, mode, null, true);
31554e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
3156cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            if (subtype != null) {
31577599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                if (imiId.equals(mCurMethodId)) {
31584e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    // The current input method is the most applicable IME.
31594e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    mostApplicableIMI = imi;
3160cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    mostApplicableSubtype = subtype;
31614e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    break;
31624e4569dab5c75804b01a19b2d6e6101b445c1c68satok                } else if (!foundInSystemIME) {
31637599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                    // The system input method is 2nd applicable IME.
31644e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    mostApplicableIMI = imi;
3165cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    mostApplicableSubtype = subtype;
31667599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                    if ((imi.getServiceInfo().applicationInfo.flags
31677599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                            & ApplicationInfo.FLAG_SYSTEM) != 0) {
31687599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                        foundInSystemIME = true;
31697599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                    }
31704e4569dab5c75804b01a19b2d6e6101b445c1c68satok                }
31714e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
31724e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
31734e4569dab5c75804b01a19b2d6e6101b445c1c68satok        if (DEBUG) {
3174cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            if (mostApplicableIMI != null) {
3175cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                Slog.w(TAG, "Most applicable shortcut input method was:"
3176cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                        + mostApplicableIMI.getId());
3177cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                if (mostApplicableSubtype != null) {
3178cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    Slog.w(TAG, "Most applicable shortcut input method subtype was:"
3179cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                            + "," + mostApplicableSubtype.getMode() + ","
3180cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                            + mostApplicableSubtype.getLocale());
3181cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                }
3182cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok            }
31834e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
3184cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok        if (mostApplicableIMI != null) {
31854e4569dab5c75804b01a19b2d6e6101b445c1c68satok            return new Pair<InputMethodInfo, InputMethodSubtype> (mostApplicableIMI,
3186cd7cd2969f545ad061a9b4ecd0044f15eb1b4abbsatok                    mostApplicableSubtype);
31874e4569dab5c75804b01a19b2d6e6101b445c1c68satok        } else {
31884e4569dab5c75804b01a19b2d6e6101b445c1c68satok            return null;
31894e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
31904e4569dab5c75804b01a19b2d6e6101b445c1c68satok    }
31914e4569dab5c75804b01a19b2d6e6101b445c1c68satok
3192ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    /**
3193ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * @return Return the current subtype of this input method.
3194ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     */
319542c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
3196ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    public InputMethodSubtype getCurrentInputMethodSubtype() {
31974e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // TODO: Make this work even for non-current users?
31984e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
31994e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return null;
32004e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
32014e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        synchronized (mMethodMap) {
32024e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return getCurrentInputMethodSubtypeLocked();
32034e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
32044e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    }
32054e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
32064e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    private InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
3207fdf419e81d795593e3792c9e78f33ed899ff098esatok        if (mCurMethodId == null) {
3208fdf419e81d795593e3792c9e78f33ed899ff098esatok            return null;
3209fdf419e81d795593e3792c9e78f33ed899ff098esatok        }
32104e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final boolean subtypeIsSelected =
32114e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                mSettings.getSelectedInputMethodSubtypeHashCode() != NOT_A_SUBTYPE_ID;
32124e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
32134e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (imi == null || imi.getSubtypeCount() == 0) {
32144e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return null;
32154e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
32164e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!subtypeIsSelected || mCurrentSubtype == null
32174e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                || !isValidSubtypeId(imi, mCurrentSubtype.hashCode())) {
32184e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            int subtypeId = getSelectedInputMethodSubtypeId(mCurMethodId);
32194e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (subtypeId == NOT_A_SUBTYPE_ID) {
32204e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                // If there are no selected subtypes, the framework will try to find
32214e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                // the most applicable subtype from explicitly or implicitly enabled
32224e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                // subtypes.
32234e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
32244e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        getEnabledInputMethodSubtypeListLocked(imi, true);
32254e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                // If there is only one explicitly or implicitly enabled subtype,
32264e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                // just returns it.
32274e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
32284e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
32294e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
32304e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mCurrentSubtype = findLastResortApplicableSubtypeLocked(
32314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                            mRes, explicitlyOrImplicitlyEnabledSubtypes,
32324e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                            SUBTYPE_MODE_KEYBOARD, null, true);
32334e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    if (mCurrentSubtype == null) {
3234fdf419e81d795593e3792c9e78f33ed899ff098esatok                        mCurrentSubtype = findLastResortApplicableSubtypeLocked(
32354e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                mRes, explicitlyOrImplicitlyEnabledSubtypes, null, null,
32364e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                                true);
32374e4569dab5c75804b01a19b2d6e6101b445c1c68satok                    }
32383ef8b29fa03fe3ae1c57fd891a12afa46128fff8satok                }
32394e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            } else {
32404e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                mCurrentSubtype = getSubtypes(imi).get(subtypeId);
32418fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok            }
32428fbb1e84ee6497f89322f2e40453c1cfa83fb4efsatok        }
32434e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        return mCurrentSubtype;
3244ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
3245ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
3246f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok    private void addShortcutInputMethodAndSubtypes(InputMethodInfo imi,
3247f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            InputMethodSubtype subtype) {
3248f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok        if (mShortcutInputMethodsAndSubtypes.containsKey(imi)) {
3249f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            mShortcutInputMethodsAndSubtypes.get(imi).add(subtype);
3250f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok        } else {
3251f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
3252f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            subtypes.add(subtype);
3253f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            mShortcutInputMethodsAndSubtypes.put(imi, subtypes);
3254f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok        }
3255f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok    }
3256f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok
32574e4569dab5c75804b01a19b2d6e6101b445c1c68satok    // TODO: We should change the return type from List to List<Parcelable>
3258dbf2950781ab0c4c0fc4ad9bd71b13c55ae6f471satok    @SuppressWarnings("rawtypes")
3259e7c6998e0a953ae55487d4fe122739646f9280aasatok    @Override
32604e4569dab5c75804b01a19b2d6e6101b445c1c68satok    public List getShortcutInputMethodsAndSubtypes() {
32614e4569dab5c75804b01a19b2d6e6101b445c1c68satok        synchronized (mMethodMap) {
32623da922367c0dbe67b97fe97fcfca13fd93602f7asatok            ArrayList<Object> ret = new ArrayList<Object>();
3263f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            if (mShortcutInputMethodsAndSubtypes.size() == 0) {
32644e4569dab5c75804b01a19b2d6e6101b445c1c68satok                // If there are no selected shortcut subtypes, the framework will try to find
32654e4569dab5c75804b01a19b2d6e6101b445c1c68satok                // the most applicable subtype from all subtypes whose mode is
32664e4569dab5c75804b01a19b2d6e6101b445c1c68satok                // SUBTYPE_MODE_VOICE. This is an exceptional case, so we will hardcode the mode.
3267f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                Pair<InputMethodInfo, InputMethodSubtype> info =
3268f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                    findLastResortApplicableShortcutInputMethodAndSubtypeLocked(
3269f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                            SUBTYPE_MODE_VOICE);
32707599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                if (info != null) {
32713da922367c0dbe67b97fe97fcfca13fd93602f7asatok                    ret.add(info.first);
32723da922367c0dbe67b97fe97fcfca13fd93602f7asatok                    ret.add(info.second);
32737599a7fb1ab5b75ca801f7d7e448f4c097320e01satok                }
32743da922367c0dbe67b97fe97fcfca13fd93602f7asatok                return ret;
3275f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            }
3276f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            for (InputMethodInfo imi: mShortcutInputMethodsAndSubtypes.keySet()) {
3277f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                ret.add(imi);
3278f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                for (InputMethodSubtype subtype: mShortcutInputMethodsAndSubtypes.get(imi)) {
3279f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok                    ret.add(subtype);
32804e4569dab5c75804b01a19b2d6e6101b445c1c68satok                }
32814e4569dab5c75804b01a19b2d6e6101b445c1c68satok            }
3282f3db1af8d55ab247b6db67baf4fe772c18f33cabsatok            return ret;
32834e4569dab5c75804b01a19b2d6e6101b445c1c68satok        }
32844e4569dab5c75804b01a19b2d6e6101b445c1c68satok    }
32854e4569dab5c75804b01a19b2d6e6101b445c1c68satok
328642c5a1666c4e576ccd5974233513100aad2c1534satok    @Override
3287b66d287e3003a0934d5714fbf15e554b3c814906satok    public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
32884e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // TODO: Make this work even for non-current users?
32894e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        if (!calledFromValidUser()) {
32904e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return false;
32914e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
3292b66d287e3003a0934d5714fbf15e554b3c814906satok        synchronized (mMethodMap) {
3293b66d287e3003a0934d5714fbf15e554b3c814906satok            if (subtype != null && mCurMethodId != null) {
3294b66d287e3003a0934d5714fbf15e554b3c814906satok                InputMethodInfo imi = mMethodMap.get(mCurMethodId);
3295b66d287e3003a0934d5714fbf15e554b3c814906satok                int subtypeId = getSubtypeIdFromHashCode(imi, subtype.hashCode());
3296b66d287e3003a0934d5714fbf15e554b3c814906satok                if (subtypeId != NOT_A_SUBTYPE_ID) {
3297b66d287e3003a0934d5714fbf15e554b3c814906satok                    setInputMethodLocked(mCurMethodId, subtypeId);
3298b66d287e3003a0934d5714fbf15e554b3c814906satok                    return true;
3299b66d287e3003a0934d5714fbf15e554b3c814906satok                }
3300b66d287e3003a0934d5714fbf15e554b3c814906satok            }
3301b66d287e3003a0934d5714fbf15e554b3c814906satok            return false;
3302b66d287e3003a0934d5714fbf15e554b3c814906satok        }
3303b66d287e3003a0934d5714fbf15e554b3c814906satok    }
3304b66d287e3003a0934d5714fbf15e554b3c814906satok
3305688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok    private static class InputMethodAndSubtypeListManager {
3306688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        private final Context mContext;
33074e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        // Used to load label
3308688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        private final PackageManager mPm;
3309688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        private final InputMethodManagerService mImms;
331093d744deb167d5c681b5bb5627fd36a92f1ea79asatok        private final String mSystemLocaleStr;
3311688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        public InputMethodAndSubtypeListManager(Context context, InputMethodManagerService imms) {
3312688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            mContext = context;
3313688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            mPm = context.getPackageManager();
3314688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            mImms = imms;
33150a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            final Locale locale = context.getResources().getConfiguration().locale;
33160a1bcf4e0d0c26af3f6ad3e57726082c92549bd3satok            mSystemLocaleStr = locale != null ? locale.toString() : "";
3317688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        }
3318688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok
3319688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        private final TreeMap<InputMethodInfo, List<InputMethodSubtype>> mSortedImmis =
3320688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                new TreeMap<InputMethodInfo, List<InputMethodSubtype>>(
3321688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        new Comparator<InputMethodInfo>() {
3322688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            @Override
3323688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            public int compare(InputMethodInfo imi1, InputMethodInfo imi2) {
3324688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                if (imi2 == null) return 0;
3325688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                if (imi1 == null) return 1;
3326688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                if (mPm == null) {
3327688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                    return imi1.getId().compareTo(imi2.getId());
3328688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                }
3329688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                CharSequence imiId1 = imi1.loadLabel(mPm) + "/" + imi1.getId();
3330688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                CharSequence imiId2 = imi2.loadLabel(mPm) + "/" + imi2.getId();
3331688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                return imiId1.toString().compareTo(imiId2.toString());
3332688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            }
3333688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        });
3334688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok
3335688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        public ImeSubtypeListItem getNextInputMethod(
3336688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
3337688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            if (imi == null) {
3338688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                return null;
3339688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            }
3340688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            final List<ImeSubtypeListItem> imList = getSortedInputMethodAndSubtypeList();
3341688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            if (imList.size() <= 1) {
3342688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                return null;
3343688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            }
3344688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            final int N = imList.size();
3345688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            final int currentSubtypeId = subtype != null
3346fdf419e81d795593e3792c9e78f33ed899ff098esatok                    ? getSubtypeIdFromHashCode(imi, subtype.hashCode())
3347688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    : NOT_A_SUBTYPE_ID;
3348688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            for (int i = 0; i < N; ++i) {
3349688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                final ImeSubtypeListItem isli = imList.get(i);
3350688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                if (isli.mImi.equals(imi) && isli.mSubtypeId == currentSubtypeId) {
3351688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    if (!onlyCurrentIme) {
3352688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        return imList.get((i + 1) % N);
3353688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    }
3354688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    for (int j = 0; j < N - 1; ++j) {
3355688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        final ImeSubtypeListItem candidate = imList.get((i + j + 1) % N);
3356688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        if (candidate.mImi.equals(imi)) {
3357688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            return candidate;
3358688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        }
3359688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    }
3360688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    return null;
3361688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                }
3362688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            }
3363688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            return null;
3364688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        }
3365688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok
3366688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList() {
3367688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            return getSortedInputMethodAndSubtypeList(true, false, false);
3368688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        }
3369688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok
3370688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList(boolean showSubtypes,
3371688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                boolean inputShown, boolean isScreenLocked) {
3372688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            final ArrayList<ImeSubtypeListItem> imList = new ArrayList<ImeSubtypeListItem>();
3373688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            final HashMap<InputMethodInfo, List<InputMethodSubtype>> immis =
3374688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    mImms.getExplicitlyOrImplicitlyEnabledInputMethodsAndSubtypeListLocked();
3375688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            if (immis == null || immis.size() == 0) {
3376688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                return Collections.emptyList();
3377688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            }
3378688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            mSortedImmis.clear();
3379688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            mSortedImmis.putAll(immis);
3380688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            for (InputMethodInfo imi : mSortedImmis.keySet()) {
3381688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                if (imi == null) continue;
3382688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList = immis.get(imi);
3383688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                HashSet<String> enabledSubtypeSet = new HashSet<String>();
3384688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                for (InputMethodSubtype subtype: explicitlyOrImplicitlyEnabledSubtypeList) {
3385688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
3386688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                }
3387688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                ArrayList<InputMethodSubtype> subtypes = getSubtypes(imi);
3388688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                final CharSequence imeLabel = imi.loadLabel(mPm);
3389688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                if (showSubtypes && enabledSubtypeSet.size() > 0) {
3390688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    final int subtypeCount = imi.getSubtypeCount();
3391688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    if (DEBUG) {
3392688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
3393688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    }
3394688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    for (int j = 0; j < subtypeCount; ++j) {
3395688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        final InputMethodSubtype subtype = imi.getSubtypeAt(j);
3396688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        final String subtypeHashCode = String.valueOf(subtype.hashCode());
3397688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        // We show all enabled IMEs and subtypes when an IME is shown.
3398688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        if (enabledSubtypeSet.contains(subtypeHashCode)
3399688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                && ((inputShown && !isScreenLocked) || !subtype.isAuxiliary())) {
3400688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            final CharSequence subtypeLabel =
3401688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                    subtype.overridesImplicitlyEnabledSubtype() ? null
3402688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                            : subtype.getDisplayName(mContext, imi.getPackageName(),
3403688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                                                    imi.getServiceInfo().applicationInfo);
340493d744deb167d5c681b5bb5627fd36a92f1ea79asatok                            imList.add(new ImeSubtypeListItem(imeLabel, subtypeLabel, imi, j,
340593d744deb167d5c681b5bb5627fd36a92f1ea79asatok                                    subtype.getLocale(), mSystemLocaleStr));
3406688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok
3407688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            // Removing this subtype from enabledSubtypeSet because we no longer
3408688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            // need to add an entry of this subtype to imList to avoid duplicated
3409688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            // entries.
3410688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                            enabledSubtypeSet.remove(subtypeHashCode);
3411688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                        }
3412688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                    }
3413688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                } else {
341493d744deb167d5c681b5bb5627fd36a92f1ea79asatok                    imList.add(new ImeSubtypeListItem(imeLabel, null, imi, NOT_A_SUBTYPE_ID,
341593d744deb167d5c681b5bb5627fd36a92f1ea79asatok                            null, mSystemLocaleStr));
3416688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok                }
3417688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            }
341893d744deb167d5c681b5bb5627fd36a92f1ea79asatok            Collections.sort(imList);
3419688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok            return imList;
3420688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok        }
3421688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok    }
3422688bd47fccf1a1373e6287bc49b5b33fad12b7f3satok
3423d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    /**
3424d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok     * Utility class for putting and getting settings for InputMethod
3425d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok     * TODO: Move all putters and getters of settings to this class.
3426d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok     */
3427d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    private static class InputMethodSettings {
3428d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // The string for enabled input method is saved as follows:
3429d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // example: ("ime0;subtype0;subtype1;subtype2:ime1:ime2;subtype0")
3430d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private static final char INPUT_METHOD_SEPARATER = ':';
3431d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private static final char INPUT_METHOD_SUBTYPE_SEPARATER = ';';
3432723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private final TextUtils.SimpleStringSplitter mInputMethodSplitter =
3433d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATER);
3434d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3435723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private final TextUtils.SimpleStringSplitter mSubtypeSplitter =
3436d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATER);
3437d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3438df31ae6a3011d47421a6ac10021f9649dc34a156satok        private final Resources mRes;
3439d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private final ContentResolver mResolver;
3440d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private final HashMap<String, InputMethodInfo> mMethodMap;
3441d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private final ArrayList<InputMethodInfo> mMethodList;
3442d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3443d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private String mEnabledInputMethodsStrCache;
34444e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        private int mCurrentUserId;
3445d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3446d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private static void buildEnabledInputMethodsSettingString(
3447d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                StringBuilder builder, Pair<String, ArrayList<String>> pair) {
3448d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            String id = pair.first;
3449d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            ArrayList<String> subtypes = pair.second;
3450d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            builder.append(id);
345157c767c7b7a4cdcd0c33ec453a9f2c0b853999b6satok            // Inputmethod and subtypes are saved in the settings as follows:
345257c767c7b7a4cdcd0c33ec453a9f2c0b853999b6satok            // ime0;subtype0;subtype1:ime1;subtype0:ime2:ime3;subtype0;subtype1
345357c767c7b7a4cdcd0c33ec453a9f2c0b853999b6satok            for (String subtypeId: subtypes) {
345457c767c7b7a4cdcd0c33ec453a9f2c0b853999b6satok                builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypeId);
3455d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3456d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3457d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3458d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public InputMethodSettings(
3459df31ae6a3011d47421a6ac10021f9649dc34a156satok                Resources res, ContentResolver resolver,
34604e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
34614e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                int userId) {
34624e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            setCurrentUserId(userId);
3463df31ae6a3011d47421a6ac10021f9649dc34a156satok            mRes = res;
3464d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mResolver = resolver;
3465d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mMethodMap = methodMap;
3466d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mMethodList = methodList;
3467d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3468d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
34694e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        public void setCurrentUserId(int userId) {
34704e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
34714e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "--- Swtich the current user from " + mCurrentUserId + " to "
34724e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        + userId + ", new ime = " + getSelectedInputMethod());
34734e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
34744e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            // IMMS settings are kept per user, so keep track of current user
34754e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            mCurrentUserId = userId;
34764e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
34774e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
3478d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public List<InputMethodInfo> getEnabledInputMethodListLocked() {
3479d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return createEnabledInputMethodListLocked(
3480d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    getEnabledInputMethodsAndSubtypeListLocked());
3481d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3482d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
34837f35c8cc88bea5230f001dd4356f864845d202e5satok        public List<Pair<InputMethodInfo, ArrayList<String>>>
348467ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                getEnabledInputMethodAndSubtypeHashCodeListLocked() {
348567ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            return createEnabledInputMethodAndSubtypeHashCodeListLocked(
34867f35c8cc88bea5230f001dd4356f864845d202e5satok                    getEnabledInputMethodsAndSubtypeListLocked());
34877f35c8cc88bea5230f001dd4356f864845d202e5satok        }
34887f35c8cc88bea5230f001dd4356f864845d202e5satok
348967ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok        public List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(
349067ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                InputMethodInfo imi) {
349167ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            List<Pair<String, ArrayList<String>>> imsList =
349267ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                    getEnabledInputMethodsAndSubtypeListLocked();
349367ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            ArrayList<InputMethodSubtype> enabledSubtypes =
349467ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                    new ArrayList<InputMethodSubtype>();
3495884ef9a11fb25b80630265daee46c5609707751fsatok            if (imi != null) {
3496884ef9a11fb25b80630265daee46c5609707751fsatok                for (Pair<String, ArrayList<String>> imsPair : imsList) {
3497884ef9a11fb25b80630265daee46c5609707751fsatok                    InputMethodInfo info = mMethodMap.get(imsPair.first);
3498884ef9a11fb25b80630265daee46c5609707751fsatok                    if (info != null && info.getId().equals(imi.getId())) {
3499586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                        final int subtypeCount = info.getSubtypeCount();
3500586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                        for (int i = 0; i < subtypeCount; ++i) {
3501586f051375d8d7aeece05329921f9f66fc6164cbKen Wakasa                            InputMethodSubtype ims = info.getSubtypeAt(i);
3502884ef9a11fb25b80630265daee46c5609707751fsatok                            for (String s: imsPair.second) {
3503884ef9a11fb25b80630265daee46c5609707751fsatok                                if (String.valueOf(ims.hashCode()).equals(s)) {
3504884ef9a11fb25b80630265daee46c5609707751fsatok                                    enabledSubtypes.add(ims);
3505884ef9a11fb25b80630265daee46c5609707751fsatok                                }
350667ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                            }
350767ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                        }
3508884ef9a11fb25b80630265daee46c5609707751fsatok                        break;
350967ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                    }
351067ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                }
351167ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            }
351267ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok            return enabledSubtypes;
351367ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok        }
351467ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok
3515d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // At the initial boot, the settings for input methods are not set,
3516d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        // so we need to enable IME in that case.
3517d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public void enableAllIMEsIfThereIsNoEnabledIME() {
3518d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (TextUtils.isEmpty(getEnabledInputMethodsStr())) {
3519d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                StringBuilder sb = new StringBuilder();
3520d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                final int N = mMethodList.size();
3521d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                for (int i = 0; i < N; i++) {
3522d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    InputMethodInfo imi = mMethodList.get(i);
3523d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    Slog.i(TAG, "Adding: " + imi.getId());
3524d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    if (i > 0) sb.append(':');
3525d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    sb.append(imi.getId());
3526d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
3527d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                putEnabledInputMethodsStr(sb.toString());
3528d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3529d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3530d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3531bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok        private List<Pair<String, ArrayList<String>>> getEnabledInputMethodsAndSubtypeListLocked() {
3532d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            ArrayList<Pair<String, ArrayList<String>>> imsList
3533d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    = new ArrayList<Pair<String, ArrayList<String>>>();
3534d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            final String enabledInputMethodsStr = getEnabledInputMethodsStr();
3535d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (TextUtils.isEmpty(enabledInputMethodsStr)) {
3536d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                return imsList;
3537d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3538723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mInputMethodSplitter.setString(enabledInputMethodsStr);
3539723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            while (mInputMethodSplitter.hasNext()) {
3540723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                String nextImsStr = mInputMethodSplitter.next();
3541723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                mSubtypeSplitter.setString(nextImsStr);
3542723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (mSubtypeSplitter.hasNext()) {
3543d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    ArrayList<String> subtypeHashes = new ArrayList<String>();
3544d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // The first element is ime id.
3545723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    String imeId = mSubtypeSplitter.next();
3546723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    while (mSubtypeSplitter.hasNext()) {
3547723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        subtypeHashes.add(mSubtypeSplitter.next());
3548d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    }
3549d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    imsList.add(new Pair<String, ArrayList<String>>(imeId, subtypeHashes));
3550d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
3551d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3552d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return imsList;
3553d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3554d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3555d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public void appendAndPutEnabledInputMethodLocked(String id, boolean reloadInputMethodStr) {
3556d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (reloadInputMethodStr) {
3557d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                getEnabledInputMethodsStr();
3558d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3559d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (TextUtils.isEmpty(mEnabledInputMethodsStrCache)) {
3560d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Add in the newly enabled input method.
3561d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                putEnabledInputMethodsStr(id);
3562d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            } else {
3563d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                putEnabledInputMethodsStr(
3564d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                        mEnabledInputMethodsStrCache + INPUT_METHOD_SEPARATER + id);
3565d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3566d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3567d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3568d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        /**
3569d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok         * Build and put a string of EnabledInputMethods with removing specified Id.
3570d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok         * @return the specified id was removed or not.
3571d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok         */
3572d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        public boolean buildAndPutEnabledInputMethodsStrRemovingIdLocked(
3573d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                StringBuilder builder, List<Pair<String, ArrayList<String>>> imsList, String id) {
3574d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            boolean isRemoved = false;
3575d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            boolean needsAppendSeparator = false;
3576d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            for (Pair<String, ArrayList<String>> ims: imsList) {
3577d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                String curId = ims.first;
3578d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                if (curId.equals(id)) {
3579d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // We are disabling this input method, and it is
3580d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // currently enabled.  Skip it to remove from the
3581d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    // new list.
3582d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    isRemoved = true;
3583d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                } else {
3584d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    if (needsAppendSeparator) {
3585d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                        builder.append(INPUT_METHOD_SEPARATER);
3586d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    } else {
3587d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                        needsAppendSeparator = true;
3588d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    }
3589d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    buildEnabledInputMethodsSettingString(builder, ims);
3590d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
3591d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3592d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            if (isRemoved) {
3593d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                // Update the setting with the new list of input methods.
3594d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                putEnabledInputMethodsStr(builder.toString());
3595d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3596d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return isRemoved;
3597d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3598d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3599d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private List<InputMethodInfo> createEnabledInputMethodListLocked(
3600d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                List<Pair<String, ArrayList<String>>> imsList) {
3601d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            final ArrayList<InputMethodInfo> res = new ArrayList<InputMethodInfo>();
3602d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            for (Pair<String, ArrayList<String>> ims: imsList) {
3603d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                InputMethodInfo info = mMethodMap.get(ims.first);
3604d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                if (info != null) {
3605d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                    res.add(info);
3606d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok                }
3607d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            }
3608d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return res;
3609d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3610d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
36117f35c8cc88bea5230f001dd4356f864845d202e5satok        private List<Pair<InputMethodInfo, ArrayList<String>>>
361267ddf9cbd5d7133c7f443cd3c55841ed1109c3a0satok                createEnabledInputMethodAndSubtypeHashCodeListLocked(
36137f35c8cc88bea5230f001dd4356f864845d202e5satok                        List<Pair<String, ArrayList<String>>> imsList) {
36147f35c8cc88bea5230f001dd4356f864845d202e5satok            final ArrayList<Pair<InputMethodInfo, ArrayList<String>>> res
36157f35c8cc88bea5230f001dd4356f864845d202e5satok                    = new ArrayList<Pair<InputMethodInfo, ArrayList<String>>>();
36167f35c8cc88bea5230f001dd4356f864845d202e5satok            for (Pair<String, ArrayList<String>> ims : imsList) {
36177f35c8cc88bea5230f001dd4356f864845d202e5satok                InputMethodInfo info = mMethodMap.get(ims.first);
36187f35c8cc88bea5230f001dd4356f864845d202e5satok                if (info != null) {
36197f35c8cc88bea5230f001dd4356f864845d202e5satok                    res.add(new Pair<InputMethodInfo, ArrayList<String>>(info, ims.second));
36207f35c8cc88bea5230f001dd4356f864845d202e5satok                }
36217f35c8cc88bea5230f001dd4356f864845d202e5satok            }
36227f35c8cc88bea5230f001dd4356f864845d202e5satok            return res;
36237f35c8cc88bea5230f001dd4356f864845d202e5satok        }
36247f35c8cc88bea5230f001dd4356f864845d202e5satok
3625d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private void putEnabledInputMethodsStr(String str) {
36264e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Settings.Secure.putStringForUser(
36274e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mResolver, Settings.Secure.ENABLED_INPUT_METHODS, str, mCurrentUserId);
3628d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            mEnabledInputMethodsStrCache = str;
36294e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
36304e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "putEnabledInputMethodStr: " + str);
36314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
3632d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3633d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
3634d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        private String getEnabledInputMethodsStr() {
36354e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            mEnabledInputMethodsStrCache = Settings.Secure.getStringForUser(
36364e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mResolver, Settings.Secure.ENABLED_INPUT_METHODS, mCurrentUserId);
3637723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (DEBUG) {
36384e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "getEnabledInputMethodsStr: " + mEnabledInputMethodsStrCache
36394e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        + ", " + mCurrentUserId);
3640723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3641d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok            return mEnabledInputMethodsStrCache;
3642d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok        }
3643723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3644723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private void saveSubtypeHistory(
3645723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                List<Pair<String, String>> savedImes, String newImeId, String newSubtypeId) {
3646723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            StringBuilder builder = new StringBuilder();
3647723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            boolean isImeAdded = false;
3648723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (!TextUtils.isEmpty(newImeId) && !TextUtils.isEmpty(newSubtypeId)) {
3649723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                builder.append(newImeId).append(INPUT_METHOD_SUBTYPE_SEPARATER).append(
3650723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        newSubtypeId);
3651723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                isImeAdded = true;
3652723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3653723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            for (Pair<String, String> ime: savedImes) {
3654723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                String imeId = ime.first;
3655723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                String subtypeId = ime.second;
3656723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (TextUtils.isEmpty(subtypeId)) {
3657723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    subtypeId = NOT_A_SUBTYPE_ID_STR;
3658723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
3659723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (isImeAdded) {
3660723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    builder.append(INPUT_METHOD_SEPARATER);
3661723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                } else {
3662723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    isImeAdded = true;
3663723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
3664723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                builder.append(imeId).append(INPUT_METHOD_SUBTYPE_SEPARATER).append(
3665723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        subtypeId);
3666723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3667723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // Remove the last INPUT_METHOD_SEPARATER
3668723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            putSubtypeHistoryStr(builder.toString());
3669723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3670723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3671723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public void addSubtypeToHistory(String imeId, String subtypeId) {
3672723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            List<Pair<String, String>> subtypeHistory = loadInputMethodAndSubtypeHistoryLocked();
3673723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            for (Pair<String, String> ime: subtypeHistory) {
3674723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (ime.first.equals(imeId)) {
3675723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    if (DEBUG) {
3676bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                        Slog.v(TAG, "Subtype found in the history: " + imeId + ", "
3677723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                                + ime.second);
3678723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    }
3679723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    // We should break here
3680723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    subtypeHistory.remove(ime);
3681723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    break;
3682723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
3683723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3684bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            if (DEBUG) {
3685bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                Slog.v(TAG, "Add subtype to the history: " + imeId + ", " + subtypeId);
3686bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok            }
3687723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            saveSubtypeHistory(subtypeHistory, imeId, subtypeId);
3688723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3689723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3690723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private void putSubtypeHistoryStr(String str) {
3691723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (DEBUG) {
3692723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                Slog.d(TAG, "putSubtypeHistoryStr: " + str);
3693723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
36944e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Settings.Secure.putStringForUser(
36954e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, str, mCurrentUserId);
3696723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3697723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3698723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public Pair<String, String> getLastInputMethodAndSubtypeLocked() {
3699723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // Gets the first one from the history
3700723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            return getLastSubtypeForInputMethodLockedInternal(null);
3701723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3702723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3703723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public String getLastSubtypeForInputMethodLocked(String imeId) {
3704723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            Pair<String, String> ime = getLastSubtypeForInputMethodLockedInternal(imeId);
3705723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (ime != null) {
3706723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                return ime.second;
3707723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            } else {
3708723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                return null;
3709723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3710723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3711723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3712723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private Pair<String, String> getLastSubtypeForInputMethodLockedInternal(String imeId) {
3713723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            List<Pair<String, ArrayList<String>>> enabledImes =
3714723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    getEnabledInputMethodsAndSubtypeListLocked();
3715723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            List<Pair<String, String>> subtypeHistory = loadInputMethodAndSubtypeHistoryLocked();
37164fc87d61c29886c848789208c9e32ba9ac4e5dd3satok            for (Pair<String, String> imeAndSubtype : subtypeHistory) {
3717723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                final String imeInTheHistory = imeAndSubtype.first;
3718723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                // If imeId is empty, returns the first IME and subtype in the history
3719723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (TextUtils.isEmpty(imeId) || imeInTheHistory.equals(imeId)) {
3720723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    final String subtypeInTheHistory = imeAndSubtype.second;
3721df31ae6a3011d47421a6ac10021f9649dc34a156satok                    final String subtypeHashCode =
3722df31ae6a3011d47421a6ac10021f9649dc34a156satok                            getEnabledSubtypeHashCodeForInputMethodAndSubtypeLocked(
3723df31ae6a3011d47421a6ac10021f9649dc34a156satok                                    enabledImes, imeInTheHistory, subtypeInTheHistory);
3724723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    if (!TextUtils.isEmpty(subtypeHashCode)) {
3725723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        if (DEBUG) {
3726bb4aa0683c8a0a1e617c6d5f03eda33f49b89ed9satok                            Slog.d(TAG, "Enabled subtype found in the history: " + subtypeHashCode);
3727723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        }
3728723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        return new Pair<String, String>(imeInTheHistory, subtypeHashCode);
3729723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    }
3730723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
3731723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3732723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (DEBUG) {
3733723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                Slog.d(TAG, "No enabled IME found in the history");
3734723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3735723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            return null;
3736723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3737723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3738df31ae6a3011d47421a6ac10021f9649dc34a156satok        private String getEnabledSubtypeHashCodeForInputMethodAndSubtypeLocked(List<Pair<String,
3739723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                ArrayList<String>>> enabledImes, String imeId, String subtypeHashCode) {
3740723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            for (Pair<String, ArrayList<String>> enabledIme: enabledImes) {
3741723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (enabledIme.first.equals(imeId)) {
3742f6cafb63753a26440cb3ad2e5124370aef650015satok                    final ArrayList<String> explicitlyEnabledSubtypes = enabledIme.second;
3743fdf419e81d795593e3792c9e78f33ed899ff098esatok                    final InputMethodInfo imi = mMethodMap.get(imeId);
3744f6cafb63753a26440cb3ad2e5124370aef650015satok                    if (explicitlyEnabledSubtypes.size() == 0) {
3745f6cafb63753a26440cb3ad2e5124370aef650015satok                        // If there are no explicitly enabled subtypes, applicable subtypes are
3746f6cafb63753a26440cb3ad2e5124370aef650015satok                        // enabled implicitly.
3747df31ae6a3011d47421a6ac10021f9649dc34a156satok                        // If IME is enabled and no subtypes are enabled, applicable subtypes
3748df31ae6a3011d47421a6ac10021f9649dc34a156satok                        // are enabled implicitly, so needs to treat them to be enabled.
3749a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                        if (imi != null && imi.getSubtypeCount() > 0) {
3750df31ae6a3011d47421a6ac10021f9649dc34a156satok                            List<InputMethodSubtype> implicitlySelectedSubtypes =
3751a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                                    getImplicitlyApplicableSubtypesLocked(mRes, imi);
3752df31ae6a3011d47421a6ac10021f9649dc34a156satok                            if (implicitlySelectedSubtypes != null) {
3753df31ae6a3011d47421a6ac10021f9649dc34a156satok                                final int N = implicitlySelectedSubtypes.size();
3754df31ae6a3011d47421a6ac10021f9649dc34a156satok                                for (int i = 0; i < N; ++i) {
3755df31ae6a3011d47421a6ac10021f9649dc34a156satok                                    final InputMethodSubtype st = implicitlySelectedSubtypes.get(i);
3756df31ae6a3011d47421a6ac10021f9649dc34a156satok                                    if (String.valueOf(st.hashCode()).equals(subtypeHashCode)) {
3757df31ae6a3011d47421a6ac10021f9649dc34a156satok                                        return subtypeHashCode;
3758df31ae6a3011d47421a6ac10021f9649dc34a156satok                                    }
3759df31ae6a3011d47421a6ac10021f9649dc34a156satok                                }
3760df31ae6a3011d47421a6ac10021f9649dc34a156satok                            }
3761df31ae6a3011d47421a6ac10021f9649dc34a156satok                        }
3762df31ae6a3011d47421a6ac10021f9649dc34a156satok                    } else {
3763f6cafb63753a26440cb3ad2e5124370aef650015satok                        for (String s: explicitlyEnabledSubtypes) {
3764df31ae6a3011d47421a6ac10021f9649dc34a156satok                            if (s.equals(subtypeHashCode)) {
3765df31ae6a3011d47421a6ac10021f9649dc34a156satok                                // If both imeId and subtypeId are enabled, return subtypeId.
3766fdf419e81d795593e3792c9e78f33ed899ff098esatok                                try {
3767fdf419e81d795593e3792c9e78f33ed899ff098esatok                                    final int hashCode = Integer.valueOf(subtypeHashCode);
3768fdf419e81d795593e3792c9e78f33ed899ff098esatok                                    // Check whether the subtype id is valid or not
3769fdf419e81d795593e3792c9e78f33ed899ff098esatok                                    if (isValidSubtypeId(imi, hashCode)) {
3770fdf419e81d795593e3792c9e78f33ed899ff098esatok                                        return s;
3771fdf419e81d795593e3792c9e78f33ed899ff098esatok                                    } else {
3772fdf419e81d795593e3792c9e78f33ed899ff098esatok                                        return NOT_A_SUBTYPE_ID_STR;
3773fdf419e81d795593e3792c9e78f33ed899ff098esatok                                    }
3774fdf419e81d795593e3792c9e78f33ed899ff098esatok                                } catch (NumberFormatException e) {
3775fdf419e81d795593e3792c9e78f33ed899ff098esatok                                    return NOT_A_SUBTYPE_ID_STR;
3776fdf419e81d795593e3792c9e78f33ed899ff098esatok                                }
3777df31ae6a3011d47421a6ac10021f9649dc34a156satok                            }
3778723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        }
3779723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    }
3780723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    // If imeId was enabled but subtypeId was disabled.
3781723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    return NOT_A_SUBTYPE_ID_STR;
3782723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
3783723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3784723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            // If both imeId and subtypeId are disabled, return null
3785723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            return null;
3786723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3787723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3788723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private List<Pair<String, String>> loadInputMethodAndSubtypeHistoryLocked() {
3789723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            ArrayList<Pair<String, String>> imsList = new ArrayList<Pair<String, String>>();
3790723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            final String subtypeHistoryStr = getSubtypeHistoryStr();
3791723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (TextUtils.isEmpty(subtypeHistoryStr)) {
3792723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                return imsList;
3793723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3794723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            mInputMethodSplitter.setString(subtypeHistoryStr);
3795723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            while (mInputMethodSplitter.hasNext()) {
3796723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                String nextImsStr = mInputMethodSplitter.next();
3797723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                mSubtypeSplitter.setString(nextImsStr);
3798723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                if (mSubtypeSplitter.hasNext()) {
3799723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    String subtypeId = NOT_A_SUBTYPE_ID_STR;
3800723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    // The first element is ime id.
3801723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    String imeId = mSubtypeSplitter.next();
3802723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    while (mSubtypeSplitter.hasNext()) {
3803723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        subtypeId = mSubtypeSplitter.next();
3804723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                        break;
3805723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    }
3806723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                    imsList.add(new Pair<String, String>(imeId, subtypeId));
3807723a27ef3d7c94fc666abc52e0abd5e8526acb69satok                }
3808723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
3809723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            return imsList;
3810723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3811723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3812723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        private String getSubtypeHistoryStr() {
3813723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            if (DEBUG) {
38144e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "getSubtypeHistoryStr: " + Settings.Secure.getStringForUser(
38154e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, mCurrentUserId));
3816723a27ef3d7c94fc666abc52e0abd5e8526acb69satok            }
38174e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return Settings.Secure.getStringForUser(
38184e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, mCurrentUserId);
3819723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3820723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3821723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public void putSelectedInputMethod(String imeId) {
38224e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
38234e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "putSelectedInputMethodStr: " + imeId + ", "
38244e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        + mCurrentUserId);
38254e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
38264e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Settings.Secure.putStringForUser(
38274e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mResolver, Settings.Secure.DEFAULT_INPUT_METHOD, imeId, mCurrentUserId);
3828723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3829723a27ef3d7c94fc666abc52e0abd5e8526acb69satok
3830723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        public void putSelectedSubtype(int subtypeId) {
38314e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
38324e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "putSelectedInputMethodSubtypeStr: " + subtypeId + ", "
38334e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        + mCurrentUserId);
38344e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
38354e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            Settings.Secure.putIntForUser(mResolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
38364e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    subtypeId, mCurrentUserId);
38374e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
38384e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
38394e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        public String getDisabledSystemInputMethods() {
38404e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return Settings.Secure.getStringForUser(
38414e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mResolver, Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, mCurrentUserId);
38424e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
38434e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
38444e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        public String getSelectedInputMethod() {
38454e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            if (DEBUG) {
38464e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                Slog.d(TAG, "getSelectedInputMethodStr: " + Settings.Secure.getStringForUser(
38474e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        mResolver, Settings.Secure.DEFAULT_INPUT_METHOD, mCurrentUserId)
38484e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        + ", " + mCurrentUserId);
38494e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
38504e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return Settings.Secure.getStringForUser(
38514e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                    mResolver, Settings.Secure.DEFAULT_INPUT_METHOD, mCurrentUserId);
38524e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
38534e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
38544e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        public int getSelectedInputMethodSubtypeHashCode() {
38554e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            try {
38564e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                return Settings.Secure.getIntForUser(
38574e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                        mResolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, mCurrentUserId);
38584e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            } catch (SettingNotFoundException e) {
38594e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                return NOT_A_SUBTYPE_ID;
38604e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
38614e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
38624e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka
38634e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        public int getCurrentUserId() {
38644e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            return mCurrentUserId;
3865723a27ef3d7c94fc666abc52e0abd5e8526acb69satok        }
3866d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok    }
3867d87c2594c688b4ed8fc9c14053abfbc5ea87fb5esatok
38685ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka    // TODO: Cache the state for each user and reset when the cached user is removed.
3869e7c6998e0a953ae55487d4fe122739646f9280aasatok    private static class InputMethodFileManager {
3870e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String SYSTEM_PATH = "system";
3871e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String INPUT_METHOD_PATH = "inputmethod";
3872e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ADDITIONAL_SUBTYPES_FILE_NAME = "subtypes.xml";
3873e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String NODE_SUBTYPES = "subtypes";
3874e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String NODE_SUBTYPE = "subtype";
3875e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String NODE_IMI = "imi";
3876e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ATTR_ID = "id";
3877e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ATTR_LABEL = "label";
3878e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ATTR_ICON = "icon";
3879e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ATTR_IME_SUBTYPE_LOCALE = "imeSubtypeLocale";
3880e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ATTR_IME_SUBTYPE_MODE = "imeSubtypeMode";
3881e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ATTR_IME_SUBTYPE_EXTRA_VALUE = "imeSubtypeExtraValue";
3882e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static final String ATTR_IS_AUXILIARY = "isAuxiliary";
3883e7c6998e0a953ae55487d4fe122739646f9280aasatok        private final AtomicFile mAdditionalInputMethodSubtypeFile;
3884e7c6998e0a953ae55487d4fe122739646f9280aasatok        private final HashMap<String, InputMethodInfo> mMethodMap;
3885e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka        private final HashMap<String, List<InputMethodSubtype>> mAdditionalSubtypesMap =
3886e7c6998e0a953ae55487d4fe122739646f9280aasatok                new HashMap<String, List<InputMethodSubtype>>();
38875ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka        public InputMethodFileManager(HashMap<String, InputMethodInfo> methodMap, int userId) {
3888e7c6998e0a953ae55487d4fe122739646f9280aasatok            if (methodMap == null) {
3889e7c6998e0a953ae55487d4fe122739646f9280aasatok                throw new NullPointerException("methodMap is null");
3890e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
3891e7c6998e0a953ae55487d4fe122739646f9280aasatok            mMethodMap = methodMap;
38925ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka            final File systemDir = userId == UserHandle.USER_OWNER
38935ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka                    ? new File(Environment.getDataDirectory(), SYSTEM_PATH)
38945ade83ba1233b33c5570caac6e081229e32d6cecSatoshi Kataoka                    : Environment.getUserSystemDirectory(userId);
3895e7c6998e0a953ae55487d4fe122739646f9280aasatok            final File inputMethodDir = new File(systemDir, INPUT_METHOD_PATH);
3896e7c6998e0a953ae55487d4fe122739646f9280aasatok            if (!inputMethodDir.mkdirs()) {
3897e7c6998e0a953ae55487d4fe122739646f9280aasatok                Slog.w(TAG, "Couldn't create dir.: " + inputMethodDir.getAbsolutePath());
3898e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
3899e7c6998e0a953ae55487d4fe122739646f9280aasatok            final File subtypeFile = new File(inputMethodDir, ADDITIONAL_SUBTYPES_FILE_NAME);
3900e7c6998e0a953ae55487d4fe122739646f9280aasatok            mAdditionalInputMethodSubtypeFile = new AtomicFile(subtypeFile);
3901e7c6998e0a953ae55487d4fe122739646f9280aasatok            if (!subtypeFile.exists()) {
3902e7c6998e0a953ae55487d4fe122739646f9280aasatok                // If "subtypes.xml" doesn't exist, create a blank file.
3903e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                writeAdditionalInputMethodSubtypes(
3904e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                        mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, methodMap);
3905e7c6998e0a953ae55487d4fe122739646f9280aasatok            } else {
3906e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                readAdditionalInputMethodSubtypes(
3907e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                        mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile);
3908e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
3909e7c6998e0a953ae55487d4fe122739646f9280aasatok        }
3910e7c6998e0a953ae55487d4fe122739646f9280aasatok
3911e7c6998e0a953ae55487d4fe122739646f9280aasatok        private void deleteAllInputMethodSubtypes(String imiId) {
3912e7c6998e0a953ae55487d4fe122739646f9280aasatok            synchronized (mMethodMap) {
3913e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                mAdditionalSubtypesMap.remove(imiId);
3914e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                writeAdditionalInputMethodSubtypes(
3915e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                        mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, mMethodMap);
3916e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
3917e7c6998e0a953ae55487d4fe122739646f9280aasatok        }
3918e7c6998e0a953ae55487d4fe122739646f9280aasatok
3919e7c6998e0a953ae55487d4fe122739646f9280aasatok        public void addInputMethodSubtypes(
39204a28bde70e23b2ed151d52690da702da7f23cf5esatok                InputMethodInfo imi, InputMethodSubtype[] additionalSubtypes) {
3921e7c6998e0a953ae55487d4fe122739646f9280aasatok            synchronized (mMethodMap) {
3922e7c6998e0a953ae55487d4fe122739646f9280aasatok                final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
3923e7c6998e0a953ae55487d4fe122739646f9280aasatok                final int N = additionalSubtypes.length;
3924e7c6998e0a953ae55487d4fe122739646f9280aasatok                for (int i = 0; i < N; ++i) {
3925e7c6998e0a953ae55487d4fe122739646f9280aasatok                    final InputMethodSubtype subtype = additionalSubtypes[i];
3926ed2b24ecc7842b27178fc584a9e5bd5b1ab07635satok                    if (!subtypes.contains(subtype)) {
3927e7c6998e0a953ae55487d4fe122739646f9280aasatok                        subtypes.add(subtype);
3928e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                    } else {
3929e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                        Slog.w(TAG, "Duplicated subtype definition found: "
3930e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                                + subtype.getLocale() + ", " + subtype.getMode());
3931e7c6998e0a953ae55487d4fe122739646f9280aasatok                    }
3932e7c6998e0a953ae55487d4fe122739646f9280aasatok                }
3933e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                mAdditionalSubtypesMap.put(imi.getId(), subtypes);
3934e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                writeAdditionalInputMethodSubtypes(
3935e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                        mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, mMethodMap);
3936e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
3937e7c6998e0a953ae55487d4fe122739646f9280aasatok        }
3938e7c6998e0a953ae55487d4fe122739646f9280aasatok
3939e7c6998e0a953ae55487d4fe122739646f9280aasatok        public HashMap<String, List<InputMethodSubtype>> getAllAdditionalInputMethodSubtypes() {
3940e7c6998e0a953ae55487d4fe122739646f9280aasatok            synchronized (mMethodMap) {
3941e62e6d8731ab1e02c1632ebc011792d07b902af8Satoshi Kataoka                return mAdditionalSubtypesMap;
3942e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
3943e7c6998e0a953ae55487d4fe122739646f9280aasatok        }
3944e7c6998e0a953ae55487d4fe122739646f9280aasatok
3945e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static void writeAdditionalInputMethodSubtypes(
3946e7c6998e0a953ae55487d4fe122739646f9280aasatok                HashMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile,
3947e7c6998e0a953ae55487d4fe122739646f9280aasatok                HashMap<String, InputMethodInfo> methodMap) {
3948e7c6998e0a953ae55487d4fe122739646f9280aasatok            // Safety net for the case that this function is called before methodMap is set.
3949e7c6998e0a953ae55487d4fe122739646f9280aasatok            final boolean isSetMethodMap = methodMap != null && methodMap.size() > 0;
3950e7c6998e0a953ae55487d4fe122739646f9280aasatok            FileOutputStream fos = null;
3951e7c6998e0a953ae55487d4fe122739646f9280aasatok            try {
3952e7c6998e0a953ae55487d4fe122739646f9280aasatok                fos = subtypesFile.startWrite();
3953e7c6998e0a953ae55487d4fe122739646f9280aasatok                final XmlSerializer out = new FastXmlSerializer();
3954e7c6998e0a953ae55487d4fe122739646f9280aasatok                out.setOutput(fos, "utf-8");
3955e7c6998e0a953ae55487d4fe122739646f9280aasatok                out.startDocument(null, true);
3956e7c6998e0a953ae55487d4fe122739646f9280aasatok                out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
3957e7c6998e0a953ae55487d4fe122739646f9280aasatok                out.startTag(null, NODE_SUBTYPES);
3958e7c6998e0a953ae55487d4fe122739646f9280aasatok                for (String imiId : allSubtypes.keySet()) {
3959e7c6998e0a953ae55487d4fe122739646f9280aasatok                    if (isSetMethodMap && !methodMap.containsKey(imiId)) {
3960e7c6998e0a953ae55487d4fe122739646f9280aasatok                        Slog.w(TAG, "IME uninstalled or not valid.: " + imiId);
3961e7c6998e0a953ae55487d4fe122739646f9280aasatok                        continue;
3962e7c6998e0a953ae55487d4fe122739646f9280aasatok                    }
3963e7c6998e0a953ae55487d4fe122739646f9280aasatok                    out.startTag(null, NODE_IMI);
3964e7c6998e0a953ae55487d4fe122739646f9280aasatok                    out.attribute(null, ATTR_ID, imiId);
3965e7c6998e0a953ae55487d4fe122739646f9280aasatok                    final List<InputMethodSubtype> subtypesList = allSubtypes.get(imiId);
3966e7c6998e0a953ae55487d4fe122739646f9280aasatok                    final int N = subtypesList.size();
3967e7c6998e0a953ae55487d4fe122739646f9280aasatok                    for (int i = 0; i < N; ++i) {
3968e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final InputMethodSubtype subtype = subtypesList.get(i);
3969e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.startTag(null, NODE_SUBTYPE);
3970e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.attribute(null, ATTR_ICON, String.valueOf(subtype.getIconResId()));
3971e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.attribute(null, ATTR_LABEL, String.valueOf(subtype.getNameResId()));
3972e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.attribute(null, ATTR_IME_SUBTYPE_LOCALE, subtype.getLocale());
3973e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.attribute(null, ATTR_IME_SUBTYPE_MODE, subtype.getMode());
3974e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.attribute(null, ATTR_IME_SUBTYPE_EXTRA_VALUE, subtype.getExtraValue());
3975e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.attribute(null, ATTR_IS_AUXILIARY,
3976e7c6998e0a953ae55487d4fe122739646f9280aasatok                                String.valueOf(subtype.isAuxiliary() ? 1 : 0));
3977e7c6998e0a953ae55487d4fe122739646f9280aasatok                        out.endTag(null, NODE_SUBTYPE);
3978e7c6998e0a953ae55487d4fe122739646f9280aasatok                    }
3979e7c6998e0a953ae55487d4fe122739646f9280aasatok                    out.endTag(null, NODE_IMI);
3980e7c6998e0a953ae55487d4fe122739646f9280aasatok                }
3981e7c6998e0a953ae55487d4fe122739646f9280aasatok                out.endTag(null, NODE_SUBTYPES);
3982e7c6998e0a953ae55487d4fe122739646f9280aasatok                out.endDocument();
3983e7c6998e0a953ae55487d4fe122739646f9280aasatok                subtypesFile.finishWrite(fos);
3984e7c6998e0a953ae55487d4fe122739646f9280aasatok            } catch (java.io.IOException e) {
3985e7c6998e0a953ae55487d4fe122739646f9280aasatok                Slog.w(TAG, "Error writing subtypes", e);
3986e7c6998e0a953ae55487d4fe122739646f9280aasatok                if (fos != null) {
3987e7c6998e0a953ae55487d4fe122739646f9280aasatok                    subtypesFile.failWrite(fos);
3988e7c6998e0a953ae55487d4fe122739646f9280aasatok                }
3989e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
3990e7c6998e0a953ae55487d4fe122739646f9280aasatok        }
3991e7c6998e0a953ae55487d4fe122739646f9280aasatok
3992e7c6998e0a953ae55487d4fe122739646f9280aasatok        private static void readAdditionalInputMethodSubtypes(
3993e7c6998e0a953ae55487d4fe122739646f9280aasatok                HashMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile) {
3994e7c6998e0a953ae55487d4fe122739646f9280aasatok            if (allSubtypes == null || subtypesFile == null) return;
3995e7c6998e0a953ae55487d4fe122739646f9280aasatok            allSubtypes.clear();
3996e7c6998e0a953ae55487d4fe122739646f9280aasatok            FileInputStream fis = null;
3997e7c6998e0a953ae55487d4fe122739646f9280aasatok            try {
3998e7c6998e0a953ae55487d4fe122739646f9280aasatok                fis = subtypesFile.openRead();
3999e7c6998e0a953ae55487d4fe122739646f9280aasatok                final XmlPullParser parser = Xml.newPullParser();
4000e7c6998e0a953ae55487d4fe122739646f9280aasatok                parser.setInput(fis, null);
4001e7c6998e0a953ae55487d4fe122739646f9280aasatok                int type = parser.getEventType();
4002e7c6998e0a953ae55487d4fe122739646f9280aasatok                // Skip parsing until START_TAG
4003e7c6998e0a953ae55487d4fe122739646f9280aasatok                while ((type = parser.next()) != XmlPullParser.START_TAG
4004e7c6998e0a953ae55487d4fe122739646f9280aasatok                        && type != XmlPullParser.END_DOCUMENT) {}
4005e7c6998e0a953ae55487d4fe122739646f9280aasatok                String firstNodeName = parser.getName();
4006e7c6998e0a953ae55487d4fe122739646f9280aasatok                if (!NODE_SUBTYPES.equals(firstNodeName)) {
4007e7c6998e0a953ae55487d4fe122739646f9280aasatok                    throw new XmlPullParserException("Xml doesn't start with subtypes");
4008e7c6998e0a953ae55487d4fe122739646f9280aasatok                }
4009e7c6998e0a953ae55487d4fe122739646f9280aasatok                final int depth =parser.getDepth();
4010e7c6998e0a953ae55487d4fe122739646f9280aasatok                String currentImiId = null;
4011e7c6998e0a953ae55487d4fe122739646f9280aasatok                ArrayList<InputMethodSubtype> tempSubtypesArray = null;
4012e7c6998e0a953ae55487d4fe122739646f9280aasatok                while (((type = parser.next()) != XmlPullParser.END_TAG
4013e7c6998e0a953ae55487d4fe122739646f9280aasatok                        || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
4014e7c6998e0a953ae55487d4fe122739646f9280aasatok                    if (type != XmlPullParser.START_TAG)
4015e7c6998e0a953ae55487d4fe122739646f9280aasatok                        continue;
4016e7c6998e0a953ae55487d4fe122739646f9280aasatok                    final String nodeName = parser.getName();
4017e7c6998e0a953ae55487d4fe122739646f9280aasatok                    if (NODE_IMI.equals(nodeName)) {
4018e7c6998e0a953ae55487d4fe122739646f9280aasatok                        currentImiId = parser.getAttributeValue(null, ATTR_ID);
4019e7c6998e0a953ae55487d4fe122739646f9280aasatok                        if (TextUtils.isEmpty(currentImiId)) {
4020e7c6998e0a953ae55487d4fe122739646f9280aasatok                            Slog.w(TAG, "Invalid imi id found in subtypes.xml");
4021e7c6998e0a953ae55487d4fe122739646f9280aasatok                            continue;
4022e7c6998e0a953ae55487d4fe122739646f9280aasatok                        }
4023e7c6998e0a953ae55487d4fe122739646f9280aasatok                        tempSubtypesArray = new ArrayList<InputMethodSubtype>();
4024e7c6998e0a953ae55487d4fe122739646f9280aasatok                        allSubtypes.put(currentImiId, tempSubtypesArray);
4025e7c6998e0a953ae55487d4fe122739646f9280aasatok                    } else if (NODE_SUBTYPE.equals(nodeName)) {
4026e7c6998e0a953ae55487d4fe122739646f9280aasatok                        if (TextUtils.isEmpty(currentImiId) || tempSubtypesArray == null) {
4027e7c6998e0a953ae55487d4fe122739646f9280aasatok                            Slog.w(TAG, "IME uninstalled or not valid.: " + currentImiId);
4028e7c6998e0a953ae55487d4fe122739646f9280aasatok                            continue;
4029e7c6998e0a953ae55487d4fe122739646f9280aasatok                        }
4030e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final int icon = Integer.valueOf(
4031e7c6998e0a953ae55487d4fe122739646f9280aasatok                                parser.getAttributeValue(null, ATTR_ICON));
4032e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final int label = Integer.valueOf(
4033e7c6998e0a953ae55487d4fe122739646f9280aasatok                                parser.getAttributeValue(null, ATTR_LABEL));
4034e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final String imeSubtypeLocale =
4035e7c6998e0a953ae55487d4fe122739646f9280aasatok                                parser.getAttributeValue(null, ATTR_IME_SUBTYPE_LOCALE);
4036e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final String imeSubtypeMode =
4037e7c6998e0a953ae55487d4fe122739646f9280aasatok                                parser.getAttributeValue(null, ATTR_IME_SUBTYPE_MODE);
4038e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final String imeSubtypeExtraValue =
4039e7c6998e0a953ae55487d4fe122739646f9280aasatok                                parser.getAttributeValue(null, ATTR_IME_SUBTYPE_EXTRA_VALUE);
40404a28bde70e23b2ed151d52690da702da7f23cf5esatok                        final boolean isAuxiliary = "1".equals(String.valueOf(
40414a28bde70e23b2ed151d52690da702da7f23cf5esatok                                parser.getAttributeValue(null, ATTR_IS_AUXILIARY)));
4042e7c6998e0a953ae55487d4fe122739646f9280aasatok                        final InputMethodSubtype subtype =
4043e7c6998e0a953ae55487d4fe122739646f9280aasatok                                new InputMethodSubtype(label, icon, imeSubtypeLocale,
4044e7c6998e0a953ae55487d4fe122739646f9280aasatok                                        imeSubtypeMode, imeSubtypeExtraValue, isAuxiliary);
4045e7c6998e0a953ae55487d4fe122739646f9280aasatok                        tempSubtypesArray.add(subtype);
4046e7c6998e0a953ae55487d4fe122739646f9280aasatok                    }
4047e7c6998e0a953ae55487d4fe122739646f9280aasatok                }
4048e7c6998e0a953ae55487d4fe122739646f9280aasatok            } catch (XmlPullParserException e) {
4049e7c6998e0a953ae55487d4fe122739646f9280aasatok                Slog.w(TAG, "Error reading subtypes: " + e);
4050e7c6998e0a953ae55487d4fe122739646f9280aasatok                return;
4051e7c6998e0a953ae55487d4fe122739646f9280aasatok            } catch (java.io.IOException e) {
4052e7c6998e0a953ae55487d4fe122739646f9280aasatok                Slog.w(TAG, "Error reading subtypes: " + e);
4053e7c6998e0a953ae55487d4fe122739646f9280aasatok                return;
4054e7c6998e0a953ae55487d4fe122739646f9280aasatok            } catch (NumberFormatException e) {
4055e7c6998e0a953ae55487d4fe122739646f9280aasatok                Slog.w(TAG, "Error reading subtypes: " + e);
4056e7c6998e0a953ae55487d4fe122739646f9280aasatok                return;
4057e7c6998e0a953ae55487d4fe122739646f9280aasatok            } finally {
4058e7c6998e0a953ae55487d4fe122739646f9280aasatok                if (fis != null) {
4059e7c6998e0a953ae55487d4fe122739646f9280aasatok                    try {
4060e7c6998e0a953ae55487d4fe122739646f9280aasatok                        fis.close();
4061e7c6998e0a953ae55487d4fe122739646f9280aasatok                    } catch (java.io.IOException e1) {
4062e7c6998e0a953ae55487d4fe122739646f9280aasatok                        Slog.w(TAG, "Failed to close.");
4063e7c6998e0a953ae55487d4fe122739646f9280aasatok                    }
4064e7c6998e0a953ae55487d4fe122739646f9280aasatok                }
4065e7c6998e0a953ae55487d4fe122739646f9280aasatok            }
4066e7c6998e0a953ae55487d4fe122739646f9280aasatok        }
4067e7c6998e0a953ae55487d4fe122739646f9280aasatok    }
4068e7c6998e0a953ae55487d4fe122739646f9280aasatok
40699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ----------------------------------------------------------------------
40704e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    // Utilities for debug
40714e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    private static String getStackTrace() {
40724e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        final StringBuilder sb = new StringBuilder();
40734e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        try {
40744e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            throw new RuntimeException();
40754e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        } catch (RuntimeException e) {
40764e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            final StackTraceElement[] frames = e.getStackTrace();
40774e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            // Start at 1 because the first frame is here and we don't care about it
40784e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            for (int j = 1; j < frames.length; ++j) {
40794e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka                sb.append(frames[j].toString() + "\n");
40804e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka            }
40814e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        }
40824e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka        return sb.toString();
40834e1ab15b305aac26ad8819fc3b2951e20985944dSatoshi Kataoka    }
4084ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
40859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
40869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
40879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
40889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                != PackageManager.PERMISSION_GRANTED) {
4089ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
40909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println("Permission Denial: can't dump InputMethodManager from from pid="
40919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + Binder.getCallingPid()
40929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + ", uid=" + Binder.getCallingUid());
40939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
40949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
40959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
40969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IInputMethod method;
40979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ClientState client;
4098ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
40999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Printer p = new PrintWriterPrinter(pw);
4100ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
41019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mMethodMap) {
41029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("Current Input Method Manager state:");
41039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int N = mMethodList.size();
41049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  Input Methods:");
41059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i=0; i<N; i++) {
41069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                InputMethodInfo info = mMethodList.get(i);
41079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("  InputMethod #" + i + ":");
41089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                info.dump(p, "    ");
41099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
41109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  Clients:");
41119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (ClientState ci : mClients.values()) {
41129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("  Client " + ci + ":");
41139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("    client=" + ci.client);
41149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("    inputContext=" + ci.inputContext);
41159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("    sessionRequested=" + ci.sessionRequested);
41169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("    curSession=" + ci.curSession);
41179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4118105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            p.println("  mCurMethodId=" + mCurMethodId);
41199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            client = mCurClient;
4120b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            p.println("  mCurClient=" + client + " mCurSeq=" + mCurSeq);
4121b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            p.println("  mCurFocusedWindow=" + mCurFocusedWindow);
41229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mCurId=" + mCurId + " mHaveConnect=" + mHaveConnection
41239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mBoundToMethod=" + mBoundToMethod);
41249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mCurToken=" + mCurToken);
41259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mCurIntent=" + mCurIntent);
41269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            method = mCurMethod;
41279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mCurMethod=" + mCurMethod);
41289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mEnabledSession=" + mEnabledSession);
41299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.println("  mShowRequested=" + mShowRequested
41309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
41319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mShowForced=" + mShowForced
41329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " mInputShown=" + mInputShown);
4133cc27870098a5b6105d6007a18bebaec8940db2d5Dianne Hackborn            p.println("  mSystemReady=" + mSystemReady + " mScreenOn=" + mScreenOn);
41349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4135ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
4136b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown        p.println(" ");
41379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (client != null) {
41389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.flush();
41399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
41409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                client.client.asBinder().dump(fd, args);
41419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
41429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("Input method client dead: " + e);
41439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4144b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown        } else {
4145b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown            p.println("No input method client.");
41469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4147ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker
4148b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown        p.println(" ");
41499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (method != null) {
41509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.flush();
41519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
41529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                method.asBinder().dump(fd, args);
41539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
41549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.println("Input method service dead: " + e);
41559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4156b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown        } else {
4157b88102f5b7e51552a3576cf197b4c8cf96f193d1Jeff Brown            p.println("No input method service.");
41589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
41599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
41609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4161