blob: 647e95284534077d5a7fea9e943457cb668bf683 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 * use this file except in compliance with the License. You may obtain a copy of
5 * the License at
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007 * http://www.apache.org/licenses/LICENSE-2.0
Doug Zongkerab5c49c2009-12-04 10:31:43 -08008 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 * License for the specific language governing permissions and limitations under
13 * the License.
14 */
15
Yohei Yukawa603f4d02018-09-11 15:04:58 -070016package com.android.server.inputmethod;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080017
lumarkef1965b2018-09-12 17:42:53 +080018import static android.view.Display.DEFAULT_DISPLAY;
lumark90120a82018-08-15 00:33:03 +080019import static android.view.Display.INVALID_DISPLAY;
Yohei Yukawaa878b952019-01-10 19:36:24 -080020import static android.view.inputmethod.InputMethodSystemProperty.PER_PROFILE_IME_ENABLED;
Yohei Yukawa0569a182018-08-28 16:09:28 -070021
Yohei Yukawafa0e47e2016-04-05 09:55:56 -070022import static java.lang.annotation.RetentionPolicy.SOURCE;
23
Yohei Yukawa926488d2017-12-11 17:24:55 -080024import android.Manifest;
Phil Weaver03a65b02018-07-19 16:07:57 -070025import android.accessibilityservice.AccessibilityService;
Tarandeep Singh75a92392018-01-12 14:58:59 -080026import android.annotation.AnyThread;
Yohei Yukawad6475a62017-04-17 10:35:27 -070027import android.annotation.BinderThread;
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +090028import android.annotation.ColorInt;
Yohei Yukawa41b094f2018-09-09 23:58:45 -070029import android.annotation.DrawableRes;
Yohei Yukawafa0e47e2016-04-05 09:55:56 -070030import android.annotation.IntDef;
Yohei Yukawa930328c2017-10-18 20:19:53 -070031import android.annotation.MainThread;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070032import android.annotation.NonNull;
Yohei Yukawae13a20fa2015-09-30 19:11:32 -070033import android.annotation.Nullable;
Yohei Yukawa926488d2017-12-11 17:24:55 -080034import android.annotation.RequiresPermission;
Yohei Yukawa7b18aec2016-03-07 13:04:32 -080035import android.annotation.UserIdInt;
Sudheer Shankadc589ac2016-11-10 15:30:17 -080036import android.app.ActivityManager;
Sudheer Shankafc46e9b2016-10-21 17:55:27 -070037import android.app.ActivityManagerInternal;
Andrew Sapperstein8a3b4cb2017-04-28 14:35:31 -070038import android.app.ActivityThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.AlertDialog;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070040import android.app.AppGlobals;
Yohei Yukawae63b5fa2014-09-19 13:14:55 +090041import android.app.AppOpsManager;
satokf90a33e2011-07-19 11:55:52 +090042import android.app.KeyguardManager;
satok7cfc0ed2011-06-20 21:29:36 +090043import android.app.Notification;
44import android.app.NotificationManager;
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070045import android.app.PendingIntent;
satok5b927c432012-05-01 20:09:34 +090046import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.content.ComponentName;
Yohei Yukawa3933a6e2016-11-10 00:47:48 -080048import android.content.ContentProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.content.ContentResolver;
50import android.content.Context;
51import android.content.DialogInterface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.content.DialogInterface.OnCancelListener;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +090053import android.content.DialogInterface.OnClickListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.content.Intent;
satoke7c6998e2011-06-03 17:57:59 +090055import android.content.IntentFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.content.ServiceConnection;
Brandon Ballinger6da35a02009-10-21 00:38:13 -070057import android.content.pm.ApplicationInfo;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +090058import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.content.pm.PackageManager;
60import android.content.pm.ResolveInfo;
61import android.content.pm.ServiceInfo;
Amith Yamasanie861ec12010-03-24 21:39:27 -070062import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.content.res.Resources;
64import android.content.res.TypedArray;
65import android.database.ContentObserver;
Alan Viverette505e3ab2014-11-24 15:22:11 -080066import android.graphics.drawable.Drawable;
Joe Onorato857fd9b2011-01-27 15:08:35 -080067import android.inputmethodservice.InputMethodService;
Michael Wright7b5a96b2014-08-09 19:28:42 -070068import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.os.Binder;
Chris Wren1ce4b6d2015-06-11 10:19:43 -040070import android.os.Bundle;
Seigo Nonakae27dc2b2015-08-14 18:21:27 -070071import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.os.Handler;
73import android.os.IBinder;
74import android.os.IInterface;
Yohei Yukawa23cbe852016-05-17 16:42:58 -070075import android.os.LocaleList;
Yohei Yukawa0569a182018-08-28 16:09:28 -070076import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077import android.os.Parcel;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070078import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079import android.os.RemoteException;
The Android Open Source Project4df24232009-03-05 14:34:35 -080080import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import android.os.ServiceManager;
Yohei Yukawa926488d2017-12-11 17:24:55 -080082import android.os.ShellCallback;
83import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084import android.os.SystemClock;
Tarandeep Singh75a92392018-01-12 14:58:59 -080085import android.os.SystemProperties;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +090086import android.os.UserHandle;
Amith Yamasani734983f2014-03-04 16:48:05 -080087import android.os.UserManager;
Yohei Yukawa42081402019-01-15 09:57:50 -080088import android.os.UserManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089import android.provider.Settings;
90import android.text.TextUtils;
satokf9f01002011-05-19 21:31:50 +090091import android.text.style.SuggestionSpan;
Yohei Yukawaac9311e2018-11-20 19:25:23 -080092import android.util.ArrayMap;
Christopher Tate7b9a28c2015-03-18 13:06:16 -070093import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.util.EventLog;
satokf9f01002011-05-19 21:31:50 +090095import android.util.LruCache;
satokab751aa2010-09-14 19:17:36 +090096import android.util.Pair;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097import android.util.PrintWriterPrinter;
98import android.util.Printer;
satoke7c6998e2011-06-03 17:57:59 +090099import android.util.Slog;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +0900100import android.view.ContextThemeWrapper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101import android.view.IWindowManager;
Jeff Brownc28867a2013-03-26 15:42:39 -0700102import android.view.InputChannel;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900103import android.view.LayoutInflater;
104import android.view.View;
105import android.view.ViewGroup;
Wale Ogunwale3a931692016-11-02 16:49:48 -0700106import android.view.Window;
Yohei Yukawa6e875592019-01-28 00:49:30 -0800107import android.view.WindowManager.LayoutParams;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700108import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
satokab751aa2010-09-14 19:17:36 +0900109import android.view.inputmethod.EditorInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import android.view.inputmethod.InputBinding;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800111import android.view.inputmethod.InputConnection;
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700112import android.view.inputmethod.InputConnectionInspector;
Yohei Yukawa432cf602018-10-21 10:41:37 -0700113import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114import android.view.inputmethod.InputMethod;
115import android.view.inputmethod.InputMethodInfo;
116import android.view.inputmethod.InputMethodManager;
satokab751aa2010-09-14 19:17:36 +0900117import android.view.inputmethod.InputMethodSubtype;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900118import android.widget.ArrayAdapter;
satok01038492012-04-09 21:08:27 +0900119import android.widget.CompoundButton;
120import android.widget.CompoundButton.OnCheckedChangeListener;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900121import android.widget.RadioButton;
satok01038492012-04-09 21:08:27 +0900122import android.widget.Switch;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900123import android.widget.TextView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124
Yohei Yukawa0569a182018-08-28 16:09:28 -0700125import com.android.internal.annotations.GuardedBy;
126import com.android.internal.content.PackageMonitor;
127import com.android.internal.inputmethod.IInputContentUriToken;
Yohei Yukawac54c1172018-09-06 11:39:50 -0700128import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
Yohei Yukawaa468d702018-10-21 11:42:34 -0700129import com.android.internal.inputmethod.InputMethodDebug;
Yohei Yukawa35fa6d52018-10-31 11:33:32 -0700130import com.android.internal.inputmethod.StartInputFlags;
Yohei Yukawac6632df2018-10-21 11:47:16 -0700131import com.android.internal.inputmethod.StartInputReason;
Yohei Yukawa499e3f72018-10-21 20:15:11 -0700132import com.android.internal.inputmethod.UnbindReason;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700133import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
134import com.android.internal.notification.SystemNotificationChannels;
135import com.android.internal.os.HandlerCaller;
136import com.android.internal.os.SomeArgs;
137import com.android.internal.os.TransferPipe;
138import com.android.internal.util.DumpUtils;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700139import com.android.internal.util.IndentingPrintWriter;
140import com.android.internal.view.IInputContext;
141import com.android.internal.view.IInputMethod;
142import com.android.internal.view.IInputMethodClient;
143import com.android.internal.view.IInputMethodManager;
144import com.android.internal.view.IInputMethodSession;
145import com.android.internal.view.IInputSessionCallback;
146import com.android.internal.view.InputBindResult;
Yohei Yukawa603f4d02018-09-11 15:04:58 -0700147import com.android.server.EventLogTags;
148import com.android.server.LocalServices;
149import com.android.server.SystemService;
Yohei Yukawae6b6e0e2018-09-12 16:42:48 -0700150import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
151import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700152import com.android.server.statusbar.StatusBarManagerService;
Adrian Roose99bc052017-11-20 17:55:31 +0100153import com.android.server.wm.WindowManagerInternal;
154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155import java.io.FileDescriptor;
156import java.io.IOException;
157import java.io.PrintWriter;
Yohei Yukawafa0e47e2016-04-05 09:55:56 -0700158import java.lang.annotation.Retention;
Yohei Yukawa25e08132016-06-22 16:31:41 -0700159import java.security.InvalidParameterException;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800160import java.text.SimpleDateFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161import java.util.ArrayList;
Yohei Yukawab8d240f2018-12-26 10:03:11 -0800162import java.util.Arrays;
satok688bd472012-02-09 20:09:17 +0900163import java.util.Collections;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800164import java.util.Date;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165import java.util.List;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800166import java.util.Locale;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800167import java.util.WeakHashMap;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800168import java.util.concurrent.atomic.AtomicInteger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169
170/**
171 * This class provides a system service that manages input methods.
172 */
173public class InputMethodManagerService extends IInputMethodManager.Stub
174 implements ServiceConnection, Handler.Callback {
175 static final boolean DEBUG = false;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700176 static final String TAG = "InputMethodManagerService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177
Yohei Yukawa926488d2017-12-11 17:24:55 -0800178 @Retention(SOURCE)
179 @IntDef({ShellCommandResult.SUCCESS, ShellCommandResult.FAILURE})
180 private @interface ShellCommandResult {
181 int SUCCESS = 0;
182 int FAILURE = -1;
183 }
184
Seigo Nonakad4474cb2015-05-04 16:53:24 -0700185 static final int MSG_SHOW_IM_SUBTYPE_PICKER = 1;
186 static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 2;
187 static final int MSG_SHOW_IM_CONFIG = 3;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 static final int MSG_UNBIND_INPUT = 1000;
190 static final int MSG_BIND_INPUT = 1010;
191 static final int MSG_SHOW_SOFT_INPUT = 1020;
192 static final int MSG_HIDE_SOFT_INPUT = 1030;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700193 static final int MSG_HIDE_CURRENT_INPUT_METHOD = 1035;
Yohei Yukawac54c1172018-09-06 11:39:50 -0700194 static final int MSG_INITIALIZE_IME = 1040;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 static final int MSG_CREATE_SESSION = 1050;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 static final int MSG_START_INPUT = 2000;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800198
Yohei Yukawa33e81792015-11-17 21:14:42 -0800199 static final int MSG_UNBIND_CLIENT = 3000;
200 static final int MSG_BIND_CLIENT = 3010;
Dianne Hackborna6e41342012-05-22 16:30:34 -0700201 static final int MSG_SET_ACTIVE = 3020;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700202 static final int MSG_SET_INTERACTIVE = 3030;
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800203 static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -0800204 static final int MSG_REPORT_PRE_RENDERED = 3060;
205 static final int MSG_APPLY_IME_VISIBILITY = 3070;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800206
satok01038492012-04-09 21:08:27 +0900207 static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
208
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -0700209 static final int MSG_SYSTEM_UNLOCK_USER = 5000;
210
Satoshi Kataokabcacc322013-10-21 17:57:27 -0700211 static final long TIME_TO_RECONNECT = 3 * 1000;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800212
satokf9f01002011-05-19 21:31:50 +0900213 static final int SECURE_SUGGESTION_SPANS_MAX_SIZE = 20;
214
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +0900215 private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
satokb6359412011-06-28 17:47:41 +0900216 private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +0900217
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700218 /**
219 * Binding flags for establishing connection to the {@link InputMethodService}.
220 */
221 private static final int IME_CONNECTION_BIND_FLAGS =
222 Context.BIND_AUTO_CREATE
223 | Context.BIND_NOT_VISIBLE
224 | Context.BIND_NOT_FOREGROUND
Yohei Yukawaad78a612017-08-04 01:57:27 -0700225 | Context.BIND_IMPORTANT_BACKGROUND;
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700226
227 /**
228 * Binding flags used only while the {@link InputMethodService} is showing window.
229 */
230 private static final int IME_VISIBLE_BIND_FLAGS =
231 Context.BIND_AUTO_CREATE
232 | Context.BIND_TREAT_LIKE_ACTIVITY
Yohei Yukawaad78a612017-08-04 01:57:27 -0700233 | Context.BIND_FOREGROUND_SERVICE
Yohei Yukawa59730962019-03-18 10:47:22 -0700234 | Context.BIND_SHOWING_UI
235 | Context.BIND_SCHEDULE_LIKE_TOP_APP;
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700236
Yohei Yukawafa0e47e2016-04-05 09:55:56 -0700237 @Retention(SOURCE)
238 @IntDef({HardKeyboardBehavior.WIRELESS_AFFORDANCE, HardKeyboardBehavior.WIRED_AFFORDANCE})
239 private @interface HardKeyboardBehavior {
240 int WIRELESS_AFFORDANCE = 0;
241 int WIRED_AFFORDANCE = 1;
242 }
satok4e4569d2010-11-19 18:45:53 +0900243
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900244 /**
245 * A protected broadcast intent action for internal use for {@link PendingIntent} in
246 * the notification.
247 */
248 private static final String ACTION_SHOW_INPUT_METHOD_PICKER =
Yohei Yukawa603f4d02018-09-11 15:04:58 -0700249 "com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER";
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900250
Tarandeep Singh75a92392018-01-12 14:58:59 -0800251 /**
252 * Debug flag for overriding runtime {@link SystemProperties}.
253 */
254 @AnyThread
255 private static final class DebugFlag {
256 private static final Object LOCK = new Object();
257 private final String mKey;
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700258 private final boolean mDefaultValue;
Tarandeep Singh75a92392018-01-12 14:58:59 -0800259 @GuardedBy("LOCK")
260 private boolean mValue;
261
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700262 public DebugFlag(String key, boolean defaultValue) {
Tarandeep Singh75a92392018-01-12 14:58:59 -0800263 mKey = key;
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700264 mDefaultValue = defaultValue;
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700265 mValue = SystemProperties.getBoolean(key, defaultValue);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800266 }
267
268 void refresh() {
269 synchronized (LOCK) {
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700270 mValue = SystemProperties.getBoolean(mKey, mDefaultValue);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800271 }
272 }
273
274 boolean value() {
275 synchronized (LOCK) {
276 return mValue;
277 }
278 }
279 }
280
281 /**
282 * Debug flags that can be overridden using "adb shell setprop <key>"
283 * Note: These flags are cached. To refresh, run "adb shell ime refresh_debug_properties".
284 */
285 private static final class DebugFlags {
286 static final DebugFlag FLAG_OPTIMIZE_START_INPUT =
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700287 new DebugFlag("debug.optimize_startinput", false);
Tarandeep Singheadb1392018-11-09 18:15:57 +0100288 static final DebugFlag FLAG_PRE_RENDER_IME_VIEWS =
289 new DebugFlag("persist.pre_render_ime_views", false);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800290 }
291
Yohei Yukawaa7babbb2019-01-08 16:45:34 -0800292 @UserIdInt
293 private int mLastSwitchUserId;
Tarandeep Singh75a92392018-01-12 14:58:59 -0800294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 final Context mContext;
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -0800296 final Resources mRes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 final Handler mHandler;
satokd87c2592010-09-29 11:52:06 +0900298 final InputMethodSettings mSettings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 final SettingsObserver mSettingsObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 final IWindowManager mIWindowManager;
Seigo Nonaka7309b122015-08-17 18:34:13 -0700301 final WindowManagerInternal mWindowManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 final HandlerCaller mCaller;
Dianne Hackborn119bbc32013-03-22 17:27:25 -0700303 final boolean mHasFeature;
Yohei Yukawab557d572018-12-29 21:26:26 -0800304 private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
305 new ArrayMap<>();
Tarandeep Singheadb1392018-11-09 18:15:57 +0100306 private final boolean mIsLowRam;
satok01038492012-04-09 21:08:27 +0900307 private final HardKeyboardListener mHardKeyboardListener;
Yohei Yukawae63b5fa2014-09-19 13:14:55 +0900308 private final AppOpsManager mAppOpsManager;
Yohei Yukawaed4952a2016-02-17 07:57:25 -0800309 private final UserManager mUserManager;
Yohei Yukawa42081402019-01-15 09:57:50 -0800310 private final UserManagerInternal mUserManagerInternal;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 // All known input methods. mMethodMap also serves as the global
313 // lock for this class.
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700314 final ArrayList<InputMethodInfo> mMethodList = new ArrayList<>();
Yohei Yukawa1dd7de62018-11-20 19:25:29 -0800315 final ArrayMap<String, InputMethodInfo> mMethodMap = new ArrayMap<>();
satokf9f01002011-05-19 21:31:50 +0900316 private final LruCache<SuggestionSpan, InputMethodInfo> mSecureSuggestionSpans =
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700317 new LruCache<>(SECURE_SUGGESTION_SPANS_MAX_SIZE);
Satoshi Kataokad787f692013-10-26 04:44:21 +0900318 private final InputMethodSubtypeSwitchingController mSwitchingController;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800319
Yohei Yukawae0733062017-02-09 22:49:35 -0800320 /**
321 * Tracks how many times {@link #mMethodMap} was updated.
322 */
323 @GuardedBy("mMethodMap")
324 private int mMethodMapUpdateCount = 0;
325
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -0700326 // Used to bring IME service up to visible adjustment while it is being shown.
327 final ServiceConnection mVisibleConnection = new ServiceConnection() {
Yohei Yukawad3ef8422018-06-07 16:28:07 -0700328 @Override public void onBindingDied(ComponentName name) {
329 synchronized (mMethodMap) {
330 if (mVisibleBound) {
331 mContext.unbindService(mVisibleConnection);
332 mVisibleBound = false;
333 }
334 }
335 }
336
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -0700337 @Override public void onServiceConnected(ComponentName name, IBinder service) {
338 }
339
340 @Override public void onServiceDisconnected(ComponentName name) {
341 }
342 };
343 boolean mVisibleBound = false;
344
satok7cfc0ed2011-06-20 21:29:36 +0900345 // Ongoing notification
Dianne Hackborn661cd522011-08-22 00:26:20 -0700346 private NotificationManager mNotificationManager;
347 private KeyguardManager mKeyguardManager;
Griff Hazen6090c262016-03-25 08:11:24 -0700348 private @Nullable StatusBarManagerService mStatusBar;
Chris Wren1ce4b6d2015-06-11 10:19:43 -0400349 private Notification.Builder mImeSwitcherNotification;
Dianne Hackborn661cd522011-08-22 00:26:20 -0700350 private PendingIntent mImeSwitchPendingIntent;
satokb858c732011-07-22 19:54:34 +0900351 private boolean mShowOngoingImeSwitcherForPhones;
satok7cfc0ed2011-06-20 21:29:36 +0900352 private boolean mNotificationShown;
353
Tadashi G. Takaoka8c6d4772014-08-05 15:29:17 +0900354 static class SessionState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 final ClientState client;
356 final IInputMethod method;
Jeff Brownc28867a2013-03-26 15:42:39 -0700357
358 IInputMethodSession session;
359 InputChannel channel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 @Override
362 public String toString() {
363 return "SessionState{uid " + client.uid + " pid " + client.pid
364 + " method " + Integer.toHexString(
365 System.identityHashCode(method))
366 + " session " + Integer.toHexString(
367 System.identityHashCode(session))
Jeff Brownc28867a2013-03-26 15:42:39 -0700368 + " channel " + channel
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 + "}";
370 }
371
372 SessionState(ClientState _client, IInputMethod _method,
Jeff Brownc28867a2013-03-26 15:42:39 -0700373 IInputMethodSession _session, InputChannel _channel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 client = _client;
375 method = _method;
376 session = _session;
Jeff Brownc28867a2013-03-26 15:42:39 -0700377 channel = _channel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 }
379 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800380
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700381 private static final class ClientDeathRecipient implements IBinder.DeathRecipient {
382 private final InputMethodManagerService mImms;
383 private final IInputMethodClient mClient;
384
385 ClientDeathRecipient(InputMethodManagerService imms, IInputMethodClient client) {
386 mImms = imms;
387 mClient = client;
388 }
389
390 @Override
391 public void binderDied() {
392 mImms.removeClient(mClient);
393 }
394 }
395
Jeff Brownc28867a2013-03-26 15:42:39 -0700396 static final class ClientState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 final IInputMethodClient client;
398 final IInputContext inputContext;
399 final int uid;
400 final int pid;
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800401 final int selfReportedDisplayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 final InputBinding binding;
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700403 final ClientDeathRecipient clientDeathRecipient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800404
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405 boolean sessionRequested;
Tarandeep Singheadb1392018-11-09 18:15:57 +0100406 // Determines if IMEs should be pre-rendered.
407 // DebugFlag can be flipped anytime. This flag is kept per-client to maintain behavior
408 // through the life of the current client.
409 boolean shouldPreRenderIme;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 SessionState curSession;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 @Override
413 public String toString() {
414 return "ClientState{" + Integer.toHexString(
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800415 System.identityHashCode(this)) + " uid=" + uid
416 + " pid=" + pid + " displayId=" + selfReportedDisplayId + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 }
418
419 ClientState(IInputMethodClient _client, IInputContext _inputContext,
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800420 int _uid, int _pid, int _selfReportedDisplayId,
421 ClientDeathRecipient _clientDeathRecipient) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 client = _client;
423 inputContext = _inputContext;
424 uid = _uid;
425 pid = _pid;
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800426 selfReportedDisplayId = _selfReportedDisplayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700428 clientDeathRecipient = _clientDeathRecipient;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 }
430 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800431
Yohei Yukawaac9311e2018-11-20 19:25:23 -0800432 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800433
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 /**
Dianne Hackborna34f1ad2009-09-02 13:26:28 -0700435 * Set once the system is ready to run third party code.
436 */
437 boolean mSystemReady;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800438
Dianne Hackborna34f1ad2009-09-02 13:26:28 -0700439 /**
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700440 * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method.
441 * method. This is to be synchronized with the secure settings keyed with
442 * {@link Settings.Secure#DEFAULT_INPUT_METHOD}.
443 *
444 * <p>This can be transiently {@code null} when the system is re-initializing input method
445 * settings, e.g., the system locale is just changed.</p>
446 *
447 * <p>Note that {@link #mCurId} is used to track which IME is being connected to
448 * {@link InputMethodManagerService}.</p>
449 *
450 * @see #mCurId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 */
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700452 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 String mCurMethodId;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800454
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 /**
456 * The current binding sequence number, incremented every time there is
457 * a new bind performed.
458 */
459 int mCurSeq;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 /**
462 * The client that is currently bound to an input method.
463 */
464 ClientState mCurClient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800465
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 /**
Yohei Yukawae39d4ed2015-11-19 03:38:49 -0800467 * The last window token that we confirmed to be focused. This is always updated upon reports
468 * from the input method client. If the window state is already changed before the report is
469 * handled, this field just keeps the last value.
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700470 */
471 IBinder mCurFocusedWindow;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800472
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700473 /**
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -0700474 * The last window token that we confirmed that IME started talking to. This is always updated
475 * upon reports from the input method. If the window state is already changed before the report
476 * is handled, this field just keeps the last value.
477 */
478 IBinder mLastImeTargetWindow;
479
480 /**
Yohei Yukawa6e875592019-01-28 00:49:30 -0800481 * {@link LayoutParams#softInputMode} of {@link #mCurFocusedWindow}.
Yohei Yukawa22a89232017-02-12 16:38:59 -0800482 *
483 * @see #mCurFocusedWindow
484 */
Yohei Yukawab0c26452018-10-21 10:42:52 -0700485 @SoftInputModeFlags
Yohei Yukawa22a89232017-02-12 16:38:59 -0800486 int mCurFocusedWindowSoftInputMode;
487
488 /**
Tarandeep Singheb570612018-01-29 16:20:32 -0800489 * The client by which {@link #mCurFocusedWindow} was reported.
Yohei Yukawae39d4ed2015-11-19 03:38:49 -0800490 */
491 ClientState mCurFocusedWindowClient;
492
493 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 * The input context last provided by the current client.
495 */
496 IInputContext mCurInputContext;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800497
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 /**
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700499 * The missing method flags for the input context last provided by the current client.
500 *
501 * @see android.view.inputmethod.InputConnectionInspector.MissingMethodFlags
502 */
Yohei Yukawa432cf602018-10-21 10:41:37 -0700503 @MissingMethodFlags
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700504 int mCurInputContextMissingMethods;
505
506 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 * The attributes last provided by the current client.
508 */
509 EditorInfo mCurAttribute;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800510
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 /**
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700512 * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 * connected to or in the process of connecting to.
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700514 *
515 * <p>This can be {@code null} when no input method is connected.</p>
516 *
517 * @see #mCurMethodId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 */
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700519 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 String mCurId;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 /**
satokab751aa2010-09-14 19:17:36 +0900523 * The current subtype of the current input method.
524 */
525 private InputMethodSubtype mCurrentSubtype;
526
John Spurlocke0980502013-10-25 11:59:29 -0400527 // Was the keyguard locked when this client became current?
528 private boolean mCurClientInKeyguard;
529
satokab751aa2010-09-14 19:17:36 +0900530 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 * Set to true if our ServiceConnection is currently actively bound to
532 * a service (whether or not we have gotten its IBinder back yet).
533 */
534 boolean mHaveConnection;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800535
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 /**
537 * Set if the client has asked for the input method to be shown.
538 */
539 boolean mShowRequested;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 /**
542 * Set if we were explicitly told to show the input method.
543 */
544 boolean mShowExplicitlyRequested;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 /**
547 * Set if we were forced to be shown.
548 */
549 boolean mShowForced;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 /**
552 * Set if we last told the input method to show itself.
553 */
554 boolean mInputShown;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 /**
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800557 * {@code true} if the current input method is in fullscreen mode.
558 */
559 boolean mInFullscreenMode;
560
561 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 * The Intent used to connect to the current input method.
563 */
564 Intent mCurIntent;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 /**
567 * The token we have made for the currently active input method, to
568 * identify it in the future.
569 */
570 IBinder mCurToken;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 /**
lumark90120a82018-08-15 00:33:03 +0800573 * The displayId of current active input method.
574 */
575 int mCurTokenDisplayId = INVALID_DISPLAY;
576
lumarkef1965b2018-09-12 17:42:53 +0800577 final ImeDisplayValidator mImeDisplayValidator;
578
lumark90120a82018-08-15 00:33:03 +0800579 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 * If non-null, this is the input method service we are currently connected
581 * to.
582 */
583 IInputMethod mCurMethod;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 /**
586 * Time that we last initiated a bind to the input method, to determine
587 * if we should try to disconnect and reconnect to it.
588 */
589 long mLastBindTime;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800590
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 /**
592 * Have we called mCurMethod.bindInput()?
593 */
594 boolean mBoundToMethod;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800595
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 /**
597 * Currently enabled session. Only touched by service thread, not
598 * protected by a lock.
599 */
600 SessionState mEnabledSession;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800601
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 /**
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700603 * True if the device is currently interactive with user. The value is true initially.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 */
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700605 boolean mIsInteractive = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800606
Joe Onorato857fd9b2011-01-27 15:08:35 -0800607 int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900608
609 /**
610 * A set of status bits regarding the active IME.
611 *
612 * <p>This value is a combination of following two bits:</p>
613 * <dl>
614 * <dt>{@link InputMethodService#IME_ACTIVE}</dt>
615 * <dd>
616 * If this bit is ON, connected IME is ready to accept touch/key events.
617 * </dd>
618 * <dt>{@link InputMethodService#IME_VISIBLE}</dt>
619 * <dd>
620 * If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
621 * </dd>
Tarandeep Singheadb1392018-11-09 18:15:57 +0100622 * dt>{@link InputMethodService#IME_INVISIBLE}</dt>
623 * <dd> If this bit is ON, IME is ready with views from last EditorInfo but is
624 * currently invisible.
625 * </dd>
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900626 * </dl>
627 * <em>Do not update this value outside of setImeWindowStatus.</em>
628 */
Joe Onorato857fd9b2011-01-27 15:08:35 -0800629 int mImeWindowVis;
630
Ken Wakasa05dbb652011-08-22 15:22:43 +0900631 private AlertDialog.Builder mDialogBuilder;
632 private AlertDialog mSwitchingDialog;
Wale Ogunwale3a931692016-11-02 16:49:48 -0700633 private IBinder mSwitchingDialogToken = new Binder();
satok01038492012-04-09 21:08:27 +0900634 private View mSwitchingDialogTitleView;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900635 private InputMethodInfo[] mIms;
636 private int[] mSubtypeIds;
Yohei Yukawae985c242016-02-24 18:27:04 -0800637 private LocaleList mLastSystemLocales;
Michael Wright7b5a96b2014-08-09 19:28:42 -0700638 private boolean mShowImeWithHardKeyboard;
Anna Galusza9b278112016-01-04 11:37:37 -0800639 private boolean mAccessibilityRequestingNoSoftKeyboard;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +0900640 private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
641 private final IPackageManager mIPackageManager;
Jason Monk3e189872016-01-12 09:10:34 -0500642 private final String mSlotIme;
Yohei Yukawafa0e47e2016-04-05 09:55:56 -0700643 @HardKeyboardBehavior
644 private final int mHardKeyboardBehavior;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800645
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800646 /**
647 * Internal state snapshot when {@link #MSG_START_INPUT} message is about to be posted to the
648 * internal message queue. Any subsequent state change inside {@link InputMethodManagerService}
649 * will not affect those tasks that are already posted.
650 *
651 * <p>Posting {@link #MSG_START_INPUT} message basically means that
652 * {@link InputMethodService#doStartInput(InputConnection, EditorInfo, boolean)} will be called
653 * back in the current IME process shortly, which will also affect what the current IME starts
654 * receiving from {@link InputMethodService#getCurrentInputConnection()}. In other words, this
655 * snapshot will be taken every time when {@link InputMethodManagerService} is initiating a new
656 * logical input session between the client application and the current IME.</p>
657 *
658 * <p>Be careful to not keep strong references to this object forever, which can prevent
659 * {@link StartInputInfo#mImeToken} and {@link StartInputInfo#mTargetWindow} from being GC-ed.
660 * </p>
661 */
662 private static class StartInputInfo {
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800663 private static final AtomicInteger sSequenceNumber = new AtomicInteger(0);
664
665 final int mSequenceNumber;
666 final long mTimestamp;
667 final long mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800668 @UserIdInt
669 final int mImeUserId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800670 @NonNull
671 final IBinder mImeToken;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800672 final int mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800673 @NonNull
674 final String mImeId;
Yohei Yukawadc66e522018-10-21 10:43:14 -0700675 @StartInputReason
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800676 final int mStartInputReason;
677 final boolean mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800678 @UserIdInt
679 final int mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800680 final int mTargetDisplayId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800681 @Nullable
682 final IBinder mTargetWindow;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800683 @NonNull
684 final EditorInfo mEditorInfo;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700685 @SoftInputModeFlags
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800686 final int mTargetWindowSoftInputMode;
687 final int mClientBindSequenceNumber;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800688
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800689 StartInputInfo(@UserIdInt int imeUserId, @NonNull IBinder imeToken, int imeDisplayId,
690 @NonNull String imeId, @StartInputReason int startInputReason, boolean restarting,
691 @UserIdInt int targetUserId, int targetDisplayId, @Nullable IBinder targetWindow,
692 @NonNull EditorInfo editorInfo, @SoftInputModeFlags int targetWindowSoftInputMode,
693 int clientBindSequenceNumber) {
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800694 mSequenceNumber = sSequenceNumber.getAndIncrement();
695 mTimestamp = SystemClock.uptimeMillis();
696 mWallTime = System.currentTimeMillis();
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800697 mImeUserId = imeUserId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800698 mImeToken = imeToken;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800699 mImeDisplayId = imeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800700 mImeId = imeId;
701 mStartInputReason = startInputReason;
702 mRestarting = restarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800703 mTargetUserId = targetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800704 mTargetDisplayId = targetDisplayId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800705 mTargetWindow = targetWindow;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800706 mEditorInfo = editorInfo;
707 mTargetWindowSoftInputMode = targetWindowSoftInputMode;
708 mClientBindSequenceNumber = clientBindSequenceNumber;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800709 }
710 }
711
Yohei Yukawab37d8bd2017-02-13 18:29:05 -0800712 @GuardedBy("mMethodMap")
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -0700713 private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800714
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800715 /**
716 * A ring buffer to store the history of {@link StartInputInfo}.
717 */
718 private static final class StartInputHistory {
719 /**
720 * Entry size for non low-RAM devices.
721 *
722 * <p>TODO: Consider to follow what other system services have been doing to manage
723 * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
724 */
725 private final static int ENTRY_SIZE_FOR_HIGH_RAM_DEVICE = 16;
726
727 /**
728 * Entry size for non low-RAM devices.
729 *
730 * <p>TODO: Consider to follow what other system services have been doing to manage
731 * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
732 */
733 private final static int ENTRY_SIZE_FOR_LOW_RAM_DEVICE = 5;
734
735 private static int getEntrySize() {
736 if (ActivityManager.isLowRamDeviceStatic()) {
737 return ENTRY_SIZE_FOR_LOW_RAM_DEVICE;
738 } else {
739 return ENTRY_SIZE_FOR_HIGH_RAM_DEVICE;
740 }
741 }
742
743 /**
744 * Backing store for the ring bugger.
745 */
746 private final Entry[] mEntries = new Entry[getEntrySize()];
747
748 /**
749 * An index of {@link #mEntries}, to which next {@link #addEntry(StartInputInfo)} should
750 * write.
751 */
752 private int mNextIndex = 0;
753
754 /**
755 * Recyclable entry to store the information in {@link StartInputInfo}.
756 */
757 private static final class Entry {
758 int mSequenceNumber;
759 long mTimestamp;
760 long mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800761 @UserIdInt
762 int mImeUserId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800763 @NonNull
764 String mImeTokenString;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800765 int mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800766 @NonNull
767 String mImeId;
Yohei Yukawadc66e522018-10-21 10:43:14 -0700768 @StartInputReason
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800769 int mStartInputReason;
770 boolean mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800771 @UserIdInt
772 int mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800773 int mTargetDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800774 @NonNull
775 String mTargetWindowString;
776 @NonNull
777 EditorInfo mEditorInfo;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700778 @SoftInputModeFlags
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800779 int mTargetWindowSoftInputMode;
780 int mClientBindSequenceNumber;
781
782 Entry(@NonNull StartInputInfo original) {
783 set(original);
784 }
785
786 void set(@NonNull StartInputInfo original) {
787 mSequenceNumber = original.mSequenceNumber;
788 mTimestamp = original.mTimestamp;
789 mWallTime = original.mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800790 mImeUserId = original.mImeUserId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800791 // Intentionally convert to String so as not to keep a strong reference to a Binder
792 // object.
793 mImeTokenString = String.valueOf(original.mImeToken);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800794 mImeDisplayId = original.mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800795 mImeId = original.mImeId;
796 mStartInputReason = original.mStartInputReason;
797 mRestarting = original.mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800798 mTargetUserId = original.mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800799 mTargetDisplayId = original.mTargetDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800800 // Intentionally convert to String so as not to keep a strong reference to a Binder
801 // object.
802 mTargetWindowString = String.valueOf(original.mTargetWindow);
803 mEditorInfo = original.mEditorInfo;
804 mTargetWindowSoftInputMode = original.mTargetWindowSoftInputMode;
805 mClientBindSequenceNumber = original.mClientBindSequenceNumber;
806 }
807 }
808
809 /**
810 * Add a new entry and discard the oldest entry as needed.
811 * @param info {@lin StartInputInfo} to be added.
812 */
813 void addEntry(@NonNull StartInputInfo info) {
814 final int index = mNextIndex;
815 if (mEntries[index] == null) {
816 mEntries[index] = new Entry(info);
817 } else {
818 mEntries[index].set(info);
819 }
820 mNextIndex = (mNextIndex + 1) % mEntries.length;
821 }
822
823 void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
824 final SimpleDateFormat dataFormat =
825 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
826
827 for (int i = 0; i < mEntries.length; ++i) {
828 final Entry entry = mEntries[(i + mNextIndex) % mEntries.length];
829 if (entry == null) {
830 continue;
831 }
832 pw.print(prefix);
833 pw.println("StartInput #" + entry.mSequenceNumber + ":");
834
835 pw.print(prefix);
836 pw.println(" time=" + dataFormat.format(new Date(entry.mWallTime))
837 + " (timestamp=" + entry.mTimestamp + ")"
838 + " reason="
Yohei Yukawaa468d702018-10-21 11:42:34 -0700839 + InputMethodDebug.startInputReasonToString(entry.mStartInputReason)
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800840 + " restarting=" + entry.mRestarting);
841
842 pw.print(prefix);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800843 pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]");
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800844 pw.print(" imeUserId=" + entry.mImeUserId);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800845 pw.println(" imeDisplayId=" + entry.mImeDisplayId);
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800846
847 pw.print(prefix);
848 pw.println(" targetWin=" + entry.mTargetWindowString
849 + " [" + entry.mEditorInfo.packageName + "]"
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800850 + " targetUserId=" + entry.mTargetUserId
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800851 + " targetDisplayId=" + entry.mTargetDisplayId
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800852 + " clientBindSeq=" + entry.mClientBindSequenceNumber);
853
854 pw.print(prefix);
Yohei Yukawaa468d702018-10-21 11:42:34 -0700855 pw.println(" softInputMode=" + InputMethodDebug.softInputModeToString(
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800856 entry.mTargetWindowSoftInputMode));
857
858 pw.print(prefix);
859 pw.println(" inputType=0x" + Integer.toHexString(entry.mEditorInfo.inputType)
860 + " imeOptions=0x" + Integer.toHexString(entry.mEditorInfo.imeOptions)
861 + " fieldId=0x" + Integer.toHexString(entry.mEditorInfo.fieldId)
862 + " fieldName=" + entry.mEditorInfo.fieldName
863 + " actionId=" + entry.mEditorInfo.actionId
864 + " actionLabel=" + entry.mEditorInfo.actionLabel);
865 }
866 }
867 }
868
869 @GuardedBy("mMethodMap")
870 @NonNull
871 private final StartInputHistory mStartInputHistory = new StartInputHistory();
872
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 class SettingsObserver extends ContentObserver {
Yohei Yukawa81482972015-06-04 00:58:59 -0700874 int mUserId;
875 boolean mRegistered = false;
Yohei Yukawa7b574cb2016-03-16 17:22:22 -0700876 @NonNull
Dianne Hackbornfd7aded2013-01-22 17:10:23 -0800877 String mLastEnabled = "";
878
Yohei Yukawa81482972015-06-04 00:58:59 -0700879 /**
880 * <em>This constructor must be called within the lock.</em>
881 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882 SettingsObserver(Handler handler) {
883 super(handler);
Yohei Yukawa81482972015-06-04 00:58:59 -0700884 }
885
Yohei Yukawa7b18aec2016-03-07 13:04:32 -0800886 public void registerContentObserverLocked(@UserIdInt int userId) {
Yohei Yukawa81482972015-06-04 00:58:59 -0700887 if (mRegistered && mUserId == userId) {
888 return;
889 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890 ContentResolver resolver = mContext.getContentResolver();
Yohei Yukawa81482972015-06-04 00:58:59 -0700891 if (mRegistered) {
892 mContext.getContentResolver().unregisterContentObserver(this);
893 mRegistered = false;
894 }
895 if (mUserId != userId) {
896 mLastEnabled = "";
897 mUserId = userId;
898 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700900 Settings.Secure.DEFAULT_INPUT_METHOD), false, this, userId);
satokab751aa2010-09-14 19:17:36 +0900901 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700902 Settings.Secure.ENABLED_INPUT_METHODS), false, this, userId);
satokb6109bb2011-02-03 22:24:54 +0900903 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700904 Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, userId);
Michael Wright7b5a96b2014-08-09 19:28:42 -0700905 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700906 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
Anna Galusza9b278112016-01-04 11:37:37 -0800907 resolver.registerContentObserver(Settings.Secure.getUriFor(
908 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, userId);
Yohei Yukawa81482972015-06-04 00:58:59 -0700909 mRegistered = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800911
Michael Wright7b5a96b2014-08-09 19:28:42 -0700912 @Override public void onChange(boolean selfChange, Uri uri) {
Anna Galusza9b278112016-01-04 11:37:37 -0800913 final Uri showImeUri = Settings.Secure.getUriFor(
914 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
915 final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
916 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 synchronized (mMethodMap) {
Michael Wright7b5a96b2014-08-09 19:28:42 -0700918 if (showImeUri.equals(uri)) {
919 updateKeyboardFromSettingsLocked();
Anna Galusza9b278112016-01-04 11:37:37 -0800920 } else if (accessibilityRequestingNoImeUri.equals(uri)) {
Phil Weaver03a65b02018-07-19 16:07:57 -0700921 final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
Anna Galusza9b278112016-01-04 11:37:37 -0800922 mContext.getContentResolver(),
Phil Weaver03a65b02018-07-19 16:07:57 -0700923 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, mUserId);
924 mAccessibilityRequestingNoSoftKeyboard =
925 (accessibilitySoftKeyboardSetting & AccessibilityService.SHOW_MODE_MASK)
926 == AccessibilityService.SHOW_MODE_HIDDEN;
Anna Galusza9b278112016-01-04 11:37:37 -0800927 if (mAccessibilityRequestingNoSoftKeyboard) {
928 final boolean showRequested = mShowRequested;
929 hideCurrentInputLocked(0, null);
930 mShowRequested = showRequested;
931 } else if (mShowRequested) {
932 showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
933 }
Michael Wright7b5a96b2014-08-09 19:28:42 -0700934 } else {
935 boolean enabledChanged = false;
936 String newEnabled = mSettings.getEnabledInputMethodsStr();
937 if (!mLastEnabled.equals(newEnabled)) {
938 mLastEnabled = newEnabled;
939 enabledChanged = true;
940 }
941 updateInputMethodsFromSettingsLocked(enabledChanged);
Dianne Hackbornfd7aded2013-01-22 17:10:23 -0800942 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 }
944 }
Yohei Yukawa81482972015-06-04 00:58:59 -0700945
946 @Override
947 public String toString() {
948 return "SettingsObserver{mUserId=" + mUserId + " mRegistered=" + mRegistered
949 + " mLastEnabled=" + mLastEnabled + "}";
950 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800952
Yohei Yukawa0ec08002019-03-08 10:48:26 -0800953 /**
954 * {@link BroadcastReceiver} that is intended to listen to broadcasts sent to the system user
955 * only.
956 */
957 private final class ImmsBroadcastReceiverForSystemUser extends BroadcastReceiver {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +0900958 @Override
959 public void onReceive(Context context, Intent intent) {
960 final String action = intent.getAction();
Yohei Yukawa4225c7d2019-03-08 00:06:11 -0800961 if (Intent.ACTION_USER_ADDED.equals(action)
Amith Yamasani734983f2014-03-04 16:48:05 -0800962 || Intent.ACTION_USER_REMOVED.equals(action)) {
Kenny Guy2a764942014-04-02 13:29:20 +0100963 updateCurrentProfileIds();
Amith Yamasani734983f2014-03-04 16:48:05 -0800964 return;
Yohei Yukawa79247822017-01-23 15:26:15 -0800965 } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
Yohei Yukawa0d7aff82017-02-10 00:40:51 -0800966 onActionLocaleChanged();
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900967 } else if (ACTION_SHOW_INPUT_METHOD_PICKER.equals(action)) {
968 // ACTION_SHOW_INPUT_METHOD_PICKER action is a protected-broadcast and it is
969 // guaranteed to be send only from the system, so that there is no need for extra
970 // security check such as
971 // {@link #canShowInputMethodPickerLocked(IInputMethodClient)}.
972 mHandler.obtainMessage(
973 MSG_SHOW_IM_SUBTYPE_PICKER,
lumark0b05f9e2018-11-26 15:09:06 +0800974 // TODO(b/120076400): Design and implement IME switcher for heterogeneous
975 // navbar configuration.
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900976 InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES,
lumark0b05f9e2018-11-26 15:09:06 +0800977 DEFAULT_DISPLAY).sendToTarget();
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +0900978 } else {
979 Slog.w(TAG, "Unexpected intent " + intent);
980 }
981 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800983
Yohei Yukawa0d7aff82017-02-10 00:40:51 -0800984 /**
Yohei Yukawa0ec08002019-03-08 10:48:26 -0800985 * {@link BroadcastReceiver} that is intended to listen to broadcasts sent to all the users.
986 */
987 private final class ImmsBroadcastReceiverForAllUsers extends BroadcastReceiver {
988 @Override
989 public void onReceive(Context context, Intent intent) {
990 final String action = intent.getAction();
991 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
992 final PendingResult pendingResult = getPendingResult();
993 if (pendingResult == null) {
994 return;
995 }
996 // sender userId can be a real user ID or USER_ALL.
997 final int senderUserId = pendingResult.getSendingUserId();
998 if (senderUserId != UserHandle.USER_ALL) {
999 final int resolvedUserId = PER_PROFILE_IME_ENABLED
1000 ? senderUserId : mUserManagerInternal.getProfileParentId(senderUserId);
1001 if (resolvedUserId != mSettings.getCurrentUserId()) {
1002 // A background user is trying to hide the dialog. Ignore.
1003 return;
1004 }
1005 }
1006 hideInputMethodMenu();
1007 } else {
1008 Slog.w(TAG, "Unexpected intent " + intent);
1009 }
1010 }
1011 }
1012
1013 /**
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001014 * Handles {@link Intent#ACTION_LOCALE_CHANGED}.
1015 *
1016 * <p>Note: For historical reasons, {@link Intent#ACTION_LOCALE_CHANGED} has been sent to all
1017 * the users. We should ignore this event if this is about any background user's locale.</p>
1018 *
1019 * <p>Caution: This method must not be called when system is not ready.</p>
1020 */
1021 void onActionLocaleChanged() {
1022 synchronized (mMethodMap) {
1023 final LocaleList possibleNewLocale = mRes.getConfiguration().getLocales();
1024 if (possibleNewLocale != null && possibleNewLocale.equals(mLastSystemLocales)) {
1025 return;
1026 }
1027 buildInputMethodListLocked(true);
1028 // If the locale is changed, needs to reset the default ime
1029 resetDefaultImeLocked(mContext);
1030 updateFromSettingsLocked(true);
1031 mLastSystemLocales = possibleNewLocale;
1032 }
1033 }
1034
Yohei Yukawac4e44912017-02-09 19:30:22 -08001035 final class MyPackageMonitor extends PackageMonitor {
1036 /**
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001037 * Package names that are known to contain {@link InputMethodService}.
Yohei Yukawac4e44912017-02-09 19:30:22 -08001038 *
1039 * <p>No need to include packages because of direct-boot unaware IMEs since we always rescan
1040 * all the packages when the user is unlocked, and direct-boot awareness will not be changed
1041 * dynamically unless the entire package is updated, which also always triggers package
1042 * rescanning.</p>
1043 */
1044 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001045 final private ArraySet<String> mKnownImePackageNames = new ArraySet<>();
1046
1047 /**
1048 * Packages that are appeared, disappeared, or modified for whatever reason.
1049 *
1050 * <p>Note: For now we intentionally use {@link ArrayList} instead of {@link ArraySet}
1051 * because 1) the number of elements is almost always 1 or so, and 2) we do not care
1052 * duplicate elements for our use case.</p>
1053 *
1054 * <p>This object must be accessed only from callback methods in {@link PackageMonitor},
1055 * which should be bound to {@link #getRegisteredHandler()}.</p>
1056 */
1057 private final ArrayList<String> mChangedPackages = new ArrayList<>();
1058
1059 /**
1060 * {@code true} if one or more packages that contain {@link InputMethodService} appeared.
1061 *
1062 * <p>This field must be accessed only from callback methods in {@link PackageMonitor},
1063 * which should be bound to {@link #getRegisteredHandler()}.</p>
1064 */
1065 private boolean mImePackageAppeared = false;
Yohei Yukawac4e44912017-02-09 19:30:22 -08001066
1067 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001068 void clearKnownImePackageNamesLocked() {
1069 mKnownImePackageNames.clear();
Yohei Yukawac4e44912017-02-09 19:30:22 -08001070 }
1071
1072 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001073 final void addKnownImePackageNameLocked(@NonNull String packageName) {
1074 mKnownImePackageNames.add(packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08001075 }
1076
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001077 @GuardedBy("mMethodMap")
1078 private boolean isChangingPackagesOfCurrentUserLocked() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001079 final int userId = getChangingUserId();
1080 final boolean retval = userId == mSettings.getCurrentUserId();
1081 if (DEBUG) {
satok81f8b7c2012-12-04 20:42:56 +09001082 if (!retval) {
1083 Slog.d(TAG, "--- ignore this call back from a background user: " + userId);
1084 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001085 }
1086 return retval;
1087 }
1088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001090 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 synchronized (mMethodMap) {
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001092 if (!isChangingPackagesOfCurrentUserLocked()) {
1093 return false;
1094 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001095 String curInputMethodId = mSettings.getSelectedInputMethod();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 final int N = mMethodList.size();
1097 if (curInputMethodId != null) {
1098 for (int i=0; i<N; i++) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001099 InputMethodInfo imi = mMethodList.get(i);
1100 if (imi.getId().equals(curInputMethodId)) {
1101 for (String pkg : packages) {
1102 if (imi.getPackageName().equals(pkg)) {
1103 if (!doit) {
1104 return true;
1105 }
satok723a27e2010-11-11 14:58:11 +09001106 resetSelectedInputMethodAndSubtypeLocked("");
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001107 chooseNewDefaultIMELocked();
1108 return true;
1109 }
1110 }
1111 }
1112 }
1113 }
1114 }
1115 return false;
1116 }
1117
1118 @Override
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001119 public void onBeginPackageChanges() {
1120 clearPackageChangeState();
1121 }
1122
1123 @Override
1124 public void onPackageAppeared(String packageName, int reason) {
1125 if (!mImePackageAppeared) {
1126 final PackageManager pm = mContext.getPackageManager();
1127 final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
1128 new Intent(InputMethod.SERVICE_INTERFACE).setPackage(packageName),
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08001129 PackageManager.MATCH_DISABLED_COMPONENTS, getChangingUserId());
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001130 // No need to lock this because we access it only on getRegisteredHandler().
1131 if (!services.isEmpty()) {
1132 mImePackageAppeared = true;
1133 }
1134 }
1135 // No need to lock this because we access it only on getRegisteredHandler().
1136 mChangedPackages.add(packageName);
1137 }
1138
1139 @Override
1140 public void onPackageDisappeared(String packageName, int reason) {
1141 // No need to lock this because we access it only on getRegisteredHandler().
1142 mChangedPackages.add(packageName);
1143 }
1144
1145 @Override
1146 public void onPackageModified(String packageName) {
1147 // No need to lock this because we access it only on getRegisteredHandler().
1148 mChangedPackages.add(packageName);
1149 }
1150
1151 @Override
1152 public void onPackagesSuspended(String[] packages) {
1153 // No need to lock this because we access it only on getRegisteredHandler().
1154 for (String packageName : packages) {
1155 mChangedPackages.add(packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08001156 }
1157 }
1158
1159 @Override
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001160 public void onPackagesUnsuspended(String[] packages) {
1161 // No need to lock this because we access it only on getRegisteredHandler().
1162 for (String packageName : packages) {
1163 mChangedPackages.add(packageName);
1164 }
1165 }
1166
1167 @Override
1168 public void onFinishPackageChanges() {
1169 onFinishPackageChangesInternal();
1170 clearPackageChangeState();
1171 }
1172
1173 private void clearPackageChangeState() {
1174 // No need to lock them because we access these fields only on getRegisteredHandler().
1175 mChangedPackages.clear();
1176 mImePackageAppeared = false;
1177 }
1178
Andreas Gampea36dc622018-02-05 17:19:22 -08001179 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001180 private boolean shouldRebuildInputMethodListLocked() {
1181 // This method is guaranteed to be called only by getRegisteredHandler().
1182
1183 // If there is any new package that contains at least one IME, then rebuilt the list
1184 // of IMEs.
1185 if (mImePackageAppeared) {
1186 return true;
1187 }
1188
1189 // Otherwise, check if mKnownImePackageNames and mChangedPackages have any intersection.
1190 // TODO: Consider to create a utility method to do the following test. List.retainAll()
1191 // is an option, but it may still do some extra operations that we do not need here.
1192 final int N = mChangedPackages.size();
1193 for (int i = 0; i < N; ++i) {
1194 final String packageName = mChangedPackages.get(i);
1195 if (mKnownImePackageNames.contains(packageName)) {
1196 return true;
1197 }
1198 }
1199 return false;
1200 }
1201
1202 private void onFinishPackageChangesInternal() {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001203 synchronized (mMethodMap) {
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001204 if (!isChangingPackagesOfCurrentUserLocked()) {
1205 return;
1206 }
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001207 if (!shouldRebuildInputMethodListLocked()) {
1208 return;
1209 }
1210
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001211 InputMethodInfo curIm = null;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001212 String curInputMethodId = mSettings.getSelectedInputMethod();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001213 final int N = mMethodList.size();
1214 if (curInputMethodId != null) {
1215 for (int i=0; i<N; i++) {
1216 InputMethodInfo imi = mMethodList.get(i);
satoke7c6998e2011-06-03 17:57:59 +09001217 final String imiId = imi.getId();
1218 if (imiId.equals(curInputMethodId)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001219 curIm = imi;
1220 }
satoke7c6998e2011-06-03 17:57:59 +09001221
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001222 int change = isPackageDisappearing(imi.getPackageName());
satoke7c6998e2011-06-03 17:57:59 +09001223 if (isPackageModified(imi.getPackageName())) {
Yohei Yukawab557d572018-12-29 21:26:26 -08001224 mAdditionalSubtypeMap.remove(imi.getId());
1225 AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
1226 mSettings.getCurrentUserId());
satoke7c6998e2011-06-03 17:57:59 +09001227 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001228 if (change == PACKAGE_TEMPORARY_CHANGE
1229 || change == PACKAGE_PERMANENT_CHANGE) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001230 Slog.i(TAG, "Input method uninstalled, disabling: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001231 + imi.getComponent());
1232 setInputMethodEnabledLocked(imi.getId(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 }
1234 }
1235 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001236
Yohei Yukawa94e33302016-02-12 19:37:03 -08001237 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 boolean changed = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001240
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001241 if (curIm != null) {
Anna Galusza9b278112016-01-04 11:37:37 -08001242 int change = isPackageDisappearing(curIm.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001243 if (change == PACKAGE_TEMPORARY_CHANGE
1244 || change == PACKAGE_PERMANENT_CHANGE) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001245 ServiceInfo si = null;
1246 try {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001247 si = mIPackageManager.getServiceInfo(
1248 curIm.getComponent(), 0, mSettings.getCurrentUserId());
1249 } catch (RemoteException ex) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001250 }
1251 if (si == null) {
1252 // Uh oh, current input method is no longer around!
1253 // Pick another one...
Joe Onorato8a9b2202010-02-26 18:56:32 -08001254 Slog.i(TAG, "Current input method removed: " + curInputMethodId);
Yohei Yukawa849443c2019-01-21 09:02:25 -08001255 updateSystemUiLocked(0 /* vis */, mBackDisposition);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001256 if (!chooseNewDefaultIMELocked()) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001257 changed = true;
1258 curIm = null;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001259 Slog.i(TAG, "Unsetting current input method");
satok723a27e2010-11-11 14:58:11 +09001260 resetSelectedInputMethodAndSubtypeLocked("");
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001261 }
1262 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001263 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001264 }
satokab751aa2010-09-14 19:17:36 +09001265
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001266 if (curIm == null) {
1267 // We currently don't have a default input method... is
1268 // one now available?
1269 changed = chooseNewDefaultIMELocked();
Yohei Yukawa54d512c2015-05-19 22:15:02 -07001270 } else if (!changed && isPackageModified(curIm.getPackageName())) {
1271 // Even if the current input method is still available, mCurrentSubtype could
1272 // be obsolete when the package is modified in practice.
1273 changed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001274 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001275
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001276 if (changed) {
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08001277 updateFromSettingsLocked(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 }
1279 }
1280 }
1281 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001282
Jeff Brownc28867a2013-03-26 15:42:39 -07001283 private static final class MethodCallback extends IInputSessionCallback.Stub {
Jean Chalarde0d32a62011-10-20 20:36:07 +09001284 private final InputMethodManagerService mParentIMMS;
Jeff Brownc28867a2013-03-26 15:42:39 -07001285 private final IInputMethod mMethod;
1286 private final InputChannel mChannel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001287
Jeff Brownc28867a2013-03-26 15:42:39 -07001288 MethodCallback(InputMethodManagerService imms, IInputMethod method,
1289 InputChannel channel) {
Jean Chalarde0d32a62011-10-20 20:36:07 +09001290 mParentIMMS = imms;
Jeff Brownc28867a2013-03-26 15:42:39 -07001291 mMethod = method;
1292 mChannel = channel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001293 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001294
satoke7c6998e2011-06-03 17:57:59 +09001295 @Override
Jeff Brownc28867a2013-03-26 15:42:39 -07001296 public void sessionCreated(IInputMethodSession session) {
Dianne Hackborn6b6b3fd2014-03-24 11:27:18 -07001297 long ident = Binder.clearCallingIdentity();
1298 try {
1299 mParentIMMS.onSessionCreated(mMethod, session, mChannel);
1300 } finally {
1301 Binder.restoreCallingIdentity(ident);
1302 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 }
1304 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001305
satok01038492012-04-09 21:08:27 +09001306 private class HardKeyboardListener
Seigo Nonaka7309b122015-08-17 18:34:13 -07001307 implements WindowManagerInternal.OnHardKeyboardStatusChangeListener {
satok01038492012-04-09 21:08:27 +09001308 @Override
Michael Wright7b5a96b2014-08-09 19:28:42 -07001309 public void onHardKeyboardStatusChange(boolean available) {
1310 mHandler.sendMessage(mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED,
1311 available ? 1 : 0));
satok01038492012-04-09 21:08:27 +09001312 }
1313
Michael Wright7b5a96b2014-08-09 19:28:42 -07001314 public void handleHardKeyboardStatusChange(boolean available) {
satok01038492012-04-09 21:08:27 +09001315 if (DEBUG) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07001316 Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
satok01038492012-04-09 21:08:27 +09001317 }
1318 synchronized(mMethodMap) {
1319 if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
1320 && mSwitchingDialog.isShowing()) {
1321 mSwitchingDialogTitleView.findViewById(
1322 com.android.internal.R.id.hard_keyboard_section).setVisibility(
1323 available ? View.VISIBLE : View.GONE);
1324 }
1325 }
1326 }
1327 }
1328
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001329 public static final class Lifecycle extends SystemService {
1330 private InputMethodManagerService mService;
1331
1332 public Lifecycle(Context context) {
1333 super(context);
1334 mService = new InputMethodManagerService(context);
1335 }
1336
1337 @Override
1338 public void onStart() {
1339 LocalServices.addService(InputMethodManagerInternal.class,
Yohei Yukawafffc0e52018-09-04 13:24:00 -07001340 new LocalServiceImpl(mService));
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001341 publishBinderService(Context.INPUT_METHOD_SERVICE, mService);
1342 }
1343
1344 @Override
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001345 public void onSwitchUser(@UserIdInt int userHandle) {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001346 // Called on ActivityManager thread.
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001347 // TODO: Dispatch this to a worker thread as needed.
1348 mService.onSwitchUser(userHandle);
1349 }
1350
1351 @Override
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001352 public void onBootPhase(int phase) {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001353 // Called on ActivityManager thread.
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001354 // TODO: Dispatch this to a worker thread as needed.
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001355 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
1356 StatusBarManagerService statusBarService = (StatusBarManagerService) ServiceManager
1357 .getService(Context.STATUS_BAR_SERVICE);
1358 mService.systemRunning(statusBarService);
1359 }
1360 }
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001361
1362 @Override
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001363 public void onUnlockUser(final @UserIdInt int userHandle) {
1364 // Called on ActivityManager thread.
1365 mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_SYSTEM_UNLOCK_USER,
Fyodor Kupolov0f57cce2016-09-09 10:36:30 -07001366 userHandle /* arg1 */, 0 /* arg2 */));
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001367 }
1368 }
1369
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001370 void onUnlockUser(@UserIdInt int userId) {
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001371 synchronized(mMethodMap) {
1372 final int currentUserId = mSettings.getCurrentUserId();
1373 if (DEBUG) {
1374 Slog.d(TAG, "onUnlockUser: userId=" + userId + " curUserId=" + currentUserId);
1375 }
1376 if (userId != currentUserId) {
1377 return;
1378 }
1379 mSettings.switchCurrentUser(currentUserId, !mSystemReady);
Yohei Yukawa79247822017-01-23 15:26:15 -08001380 if (mSystemReady) {
1381 // We need to rebuild IMEs.
1382 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
1383 updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
1384 }
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001385 }
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001386 }
1387
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001388 void onSwitchUser(@UserIdInt int userId) {
1389 synchronized (mMethodMap) {
1390 switchUserLocked(userId);
1391 }
1392 }
1393
Seigo Nonaka7309b122015-08-17 18:34:13 -07001394 public InputMethodManagerService(Context context) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001395 mIPackageManager = AppGlobals.getPackageManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 mContext = context;
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -08001397 mRes = context.getResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 mHandler = new Handler(this);
Yohei Yukawa81482972015-06-04 00:58:59 -07001399 // Note: SettingsObserver doesn't register observers in its constructor.
1400 mSettingsObserver = new SettingsObserver(mHandler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 mIWindowManager = IWindowManager.Stub.asInterface(
1402 ServiceManager.getService(Context.WINDOW_SERVICE));
Seigo Nonaka7309b122015-08-17 18:34:13 -07001403 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
Andrii Kuliandd989612019-02-21 12:13:28 -08001404 mImeDisplayValidator = mWindowManagerInternal::shouldShowSystemDecorOnDisplay;
Mita Yuned218c72012-12-06 17:18:25 -08001405 mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
satoke7c6998e2011-06-03 17:57:59 +09001406 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001407 public void executeMessage(Message msg) {
1408 handleMessage(msg);
1409 }
Mita Yuned218c72012-12-06 17:18:25 -08001410 }, true /*asyncHandler*/);
Yohei Yukawad34e1482016-02-11 08:03:52 -08001411 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001412 mUserManager = mContext.getSystemService(UserManager.class);
Yohei Yukawa42081402019-01-15 09:57:50 -08001413 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
satok01038492012-04-09 21:08:27 +09001414 mHardKeyboardListener = new HardKeyboardListener();
Dianne Hackborn119bbc32013-03-22 17:27:25 -07001415 mHasFeature = context.getPackageManager().hasSystemFeature(
1416 PackageManager.FEATURE_INPUT_METHODS);
Jason Monk3e189872016-01-12 09:10:34 -05001417 mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
Yohei Yukawafa0e47e2016-04-05 09:55:56 -07001418 mHardKeyboardBehavior = mContext.getResources().getInteger(
1419 com.android.internal.R.integer.config_externalHardKeyboardBehavior);
Tarandeep Singheadb1392018-11-09 18:15:57 +01001420 mIsLowRam = ActivityManager.isLowRamDeviceStatic();
satok7cfc0ed2011-06-20 21:29:36 +09001421
Chris Wren1ce4b6d2015-06-11 10:19:43 -04001422 Bundle extras = new Bundle();
1423 extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001424 @ColorInt final int accentColor = mContext.getColor(
1425 com.android.internal.R.color.system_notification_accent_color);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001426 mImeSwitcherNotification =
1427 new Notification.Builder(mContext, SystemNotificationChannels.VIRTUAL_KEYBOARD)
1428 .setSmallIcon(com.android.internal.R.drawable.ic_notification_ime_default)
1429 .setWhen(0)
1430 .setOngoing(true)
1431 .addExtras(extras)
1432 .setCategory(Notification.CATEGORY_SYSTEM)
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001433 .setColor(accentColor);
Daniel Sandler590d5152012-06-14 16:10:13 -04001434
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001435 Intent intent = new Intent(ACTION_SHOW_INPUT_METHOD_PICKER)
1436 .setPackage(mContext.getPackageName());
satok683e2382011-07-12 08:28:52 +09001437 mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
satokb858c732011-07-22 19:54:34 +09001438
1439 mShowOngoingImeSwitcherForPhones = false;
satok7cfc0ed2011-06-20 21:29:36 +09001440
satok7cfc0ed2011-06-20 21:29:36 +09001441 mNotificationShown = false;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001442 int userId = 0;
1443 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001444 userId = ActivityManager.getService().getCurrentUser().id;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001445 } catch (RemoteException e) {
1446 Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
1447 }
satok913a8922010-08-26 21:53:41 +09001448
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08001449 mLastSwitchUserId = userId;
1450
satokd87c2592010-09-29 11:52:06 +09001451 // mSettings should be created before buildInputMethodListLocked
satokdf31ae62011-01-15 06:19:44 +09001452 mSettings = new InputMethodSettings(
Yohei Yukawaf9277532019-01-25 02:47:32 -08001453 mRes, context.getContentResolver(), mMethodMap, userId, !mSystemReady);
Svet Ganovadc1cf42015-06-15 16:36:24 -07001454
Kenny Guy2a764942014-04-02 13:29:20 +01001455 updateCurrentProfileIds();
Yohei Yukawab557d572018-12-29 21:26:26 -08001456 AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
Yohei Yukawa79247822017-01-23 15:26:15 -08001457 mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
1458 mSettings, context);
satok5b927c432012-05-01 20:09:34 +09001459 }
1460
satok5b927c432012-05-01 20:09:34 +09001461 private void resetDefaultImeLocked(Context context) {
1462 // Do not reset the default (current) IME when it is a 3rd-party IME
Yohei Yukawafd70fe82018-04-08 12:19:56 -07001463 if (mCurMethodId != null && !mMethodMap.get(mCurMethodId).isSystem()) {
satok5b927c432012-05-01 20:09:34 +09001464 return;
1465 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001466 final List<InputMethodInfo> suitableImes = InputMethodUtils.getDefaultEnabledImes(
Yohei Yukawaaf5cee82017-01-23 16:17:11 -08001467 context, mSettings.getEnabledInputMethodListLocked());
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001468 if (suitableImes.isEmpty()) {
1469 Slog.i(TAG, "No default found");
1470 return;
satok5b927c432012-05-01 20:09:34 +09001471 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001472 final InputMethodInfo defIm = suitableImes.get(0);
Yohei Yukawad0332832017-02-01 13:59:43 -08001473 if (DEBUG) {
1474 Slog.i(TAG, "Default found, using " + defIm.getId());
1475 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001476 setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
satok5b927c432012-05-01 20:09:34 +09001477 }
1478
Andreas Gampea36dc622018-02-05 17:19:22 -08001479 @GuardedBy("mMethodMap")
Satoshi Kataoka5ade83b2012-09-26 22:59:41 +09001480 private void switchUserLocked(int newUserId) {
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001481 if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
1482 + " currentUserId=" + mSettings.getCurrentUserId());
1483
Yohei Yukawa81482972015-06-04 00:58:59 -07001484 // ContentObserver should be registered again when the user is changed
1485 mSettingsObserver.registerContentObserverLocked(newUserId);
Yohei Yukawa68645a62016-02-17 07:54:20 -08001486
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001487 // If the system is not ready or the device is not yed unlocked by the user, then we use
1488 // copy-on-write settings.
1489 final boolean useCopyOnWriteSettings =
Yohei Yukawa42081402019-01-15 09:57:50 -08001490 !mSystemReady || !mUserManagerInternal.isUserUnlockingOrUnlocked(newUserId);
Yohei Yukawa68645a62016-02-17 07:54:20 -08001491 mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
Kenny Guy2a764942014-04-02 13:29:20 +01001492 updateCurrentProfileIds();
Yohei Yukawab557d572018-12-29 21:26:26 -08001493 // Additional subtypes should be reset when the user is changed
1494 AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, newUserId);
Satoshi Kataoka7f7535f2013-02-18 12:54:16 +09001495 final String defaultImiId = mSettings.getSelectedInputMethod();
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001496
1497 if (DEBUG) Slog.d(TAG, "Switching user stage 2/3. newUserId=" + newUserId
1498 + " defaultImiId=" + defaultImiId);
1499
Satoshi Kataoka7c4a2a12013-02-25 15:25:43 +09001500 // For secondary users, the list of enabled IMEs may not have been updated since the
1501 // callbacks to PackageMonitor are ignored for the secondary user. Here, defaultImiId may
1502 // not be empty even if the IME has been uninstalled by the primary user.
1503 // Even in such cases, IMMS works fine because it will find the most applicable
1504 // IME for that user.
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001505 final boolean initialUserSwitch = TextUtils.isEmpty(defaultImiId);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001506 mLastSystemLocales = mRes.getConfiguration().getLocales();
1507
1508 // TODO: Is it really possible that switchUserLocked() happens before system ready?
1509 if (mSystemReady) {
1510 hideCurrentInputLocked(0, null);
Yohei Yukawab7526452018-10-21 20:15:17 -07001511 resetCurrentMethodAndClient(UnbindReason.SWITCH_USER);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001512 buildInputMethodListLocked(initialUserSwitch);
1513 if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) {
1514 // This is the first time of the user switch and
1515 // set the current ime to the proper one.
1516 resetDefaultImeLocked(mContext);
1517 }
1518 updateFromSettingsLocked(true);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001519 }
1520
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001521 if (initialUserSwitch) {
Yohei Yukawa094c71f2015-06-20 00:41:31 -07001522 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
1523 mSettings.getEnabledInputMethodListLocked(), newUserId,
1524 mContext.getBasePackageName());
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001525 }
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001526
1527 if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId
1528 + " selectedIme=" + mSettings.getSelectedInputMethod());
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08001529
1530 mLastSwitchUserId = newUserId;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001531 }
1532
Kenny Guy2a764942014-04-02 13:29:20 +01001533 void updateCurrentProfileIds() {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -07001534 mSettings.setCurrentProfileIds(
1535 mUserManager.getProfileIdsWithDisabled(mSettings.getCurrentUserId()));
Amith Yamasani734983f2014-03-04 16:48:05 -08001536 }
1537
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 @Override
1539 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1540 throws RemoteException {
1541 try {
1542 return super.onTransact(code, data, reply, flags);
1543 } catch (RuntimeException e) {
1544 // The input method manager only throws security exceptions, so let's
1545 // log all others.
1546 if (!(e instanceof SecurityException)) {
Dianne Hackborn164371f2013-10-01 19:10:13 -07001547 Slog.wtf(TAG, "Input Method Manager Crash", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548 }
1549 throw e;
1550 }
1551 }
1552
Svetoslav Ganova0027152013-06-25 14:59:53 -07001553 public void systemRunning(StatusBarManagerService statusBar) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001554 synchronized (mMethodMap) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001555 if (DEBUG) {
1556 Slog.d(TAG, "--- systemReady");
1557 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001558 if (!mSystemReady) {
1559 mSystemReady = true;
Yohei Yukawa79247822017-01-23 15:26:15 -08001560 mLastSystemLocales = mRes.getConfiguration().getLocales();
Yohei Yukawa68645a62016-02-17 07:54:20 -08001561 final int currentUserId = mSettings.getCurrentUserId();
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001562 mSettings.switchCurrentUser(currentUserId,
Yohei Yukawa42081402019-01-15 09:57:50 -08001563 !mUserManagerInternal.isUserUnlockingOrUnlocked(currentUserId));
Yohei Yukawad34e1482016-02-11 08:03:52 -08001564 mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
1565 mNotificationManager = mContext.getSystemService(NotificationManager.class);
Dianne Hackborn661cd522011-08-22 00:26:20 -07001566 mStatusBar = statusBar;
Griff Hazen6090c262016-03-25 08:11:24 -07001567 if (mStatusBar != null) {
1568 mStatusBar.setIconVisibility(mSlotIme, false);
1569 }
Yohei Yukawa849443c2019-01-21 09:02:25 -08001570 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
satokb858c732011-07-22 19:54:34 +09001571 mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
1572 com.android.internal.R.bool.show_ongoing_ime_switcher);
satok01038492012-04-09 21:08:27 +09001573 if (mShowOngoingImeSwitcherForPhones) {
Seigo Nonaka7309b122015-08-17 18:34:13 -07001574 mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
satok01038492012-04-09 21:08:27 +09001575 mHardKeyboardListener);
1576 }
Yohei Yukawa79247822017-01-23 15:26:15 -08001577
1578 mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
1579 mSettingsObserver.registerContentObserverLocked(currentUserId);
1580
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001581 final IntentFilter broadcastFilterForSystemUser = new IntentFilter();
1582 broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_ADDED);
1583 broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_REMOVED);
1584 broadcastFilterForSystemUser.addAction(Intent.ACTION_LOCALE_CHANGED);
1585 broadcastFilterForSystemUser.addAction(ACTION_SHOW_INPUT_METHOD_PICKER);
1586 mContext.registerReceiver(new ImmsBroadcastReceiverForSystemUser(),
1587 broadcastFilterForSystemUser);
1588
1589 final IntentFilter broadcastFilterForAllUsers = new IntentFilter();
1590 broadcastFilterForAllUsers.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
1591 mContext.registerReceiverAsUser(new ImmsBroadcastReceiverForAllUsers(),
1592 UserHandle.ALL, broadcastFilterForAllUsers, null, null);
Yohei Yukawa79247822017-01-23 15:26:15 -08001593
Yohei Yukawa1f9a3cb2017-10-26 15:00:59 -07001594 final String defaultImiId = mSettings.getSelectedInputMethod();
1595 final boolean imeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
1596 buildInputMethodListLocked(!imeSelectedOnBoot /* resetDefaultEnabledIme */);
Yohei Yukawa79247822017-01-23 15:26:15 -08001597 updateFromSettingsLocked(true);
1598 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
1599 mSettings.getEnabledInputMethodListLocked(), currentUserId,
1600 mContext.getBasePackageName());
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001601 }
1602 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001604
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001605 // ---------------------------------------------------------------------------------------
1606 // Check whether or not this is a valid IPC. Assumes an IPC is valid when either
1607 // 1) it comes from the system process
1608 // 2) the calling process' user id is identical to the current user id IMMS thinks.
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001609 @GuardedBy("mMethodMap")
Yohei Yukawa46d74762019-01-22 10:17:22 -08001610 private boolean calledFromValidUserLocked() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001611 final int uid = Binder.getCallingUid();
1612 final int userId = UserHandle.getUserId(uid);
1613 if (DEBUG) {
1614 Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
1615 + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
1616 + " calling userId = " + userId + ", foreground user id = "
Satoshi Kataoka87c29142013-07-31 23:11:54 +09001617 + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid()
1618 + InputMethodUtils.getApiCallStack());
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001619 }
Yohei Yukawaa878b952019-01-10 19:36:24 -08001620 if (uid == Process.SYSTEM_UID) {
1621 return true;
1622 }
1623 if (userId == mSettings.getCurrentUserId()) {
1624 return true;
1625 }
Yohei Yukawa46d74762019-01-22 10:17:22 -08001626 if (!PER_PROFILE_IME_ENABLED && mSettings.isCurrentProfile(userId)) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001627 return true;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001628 }
Satoshi Kataoka135e5fb2012-09-28 18:25:06 +09001629
1630 // Caveat: A process which has INTERACT_ACROSS_USERS_FULL gets results for the
1631 // foreground user, not for the user of that process. Accordingly InputMethodManagerService
1632 // must not manage background users' states in any functions.
1633 // Note that privacy-sensitive IPCs, such as setInputMethod, are still securely guarded
1634 // by a token.
1635 if (mContext.checkCallingOrSelfPermission(
1636 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1637 == PackageManager.PERMISSION_GRANTED) {
1638 if (DEBUG) {
1639 Slog.d(TAG, "--- Access granted because the calling process has "
1640 + "the INTERACT_ACROSS_USERS_FULL permission");
1641 }
1642 return true;
1643 }
Yohei Yukawad0332832017-02-01 13:59:43 -08001644 // TODO(b/34886274): The semantics of this verification is actually not well-defined.
Seigo Nonakae27dc2b2015-08-14 18:21:27 -07001645 Slog.w(TAG, "--- IPC called from background users. Ignore. callers="
1646 + Debug.getCallers(10));
Satoshi Kataoka135e5fb2012-09-28 18:25:06 +09001647 return false;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001648 }
1649
Yohei Yukawa22c97be2014-06-04 19:43:36 +09001650
1651 /**
1652 * Returns true iff the caller is identified to be the current input method with the token.
1653 * @param token The window token given to the input method when it was started.
1654 * @return true if and only if non-null valid token is specified.
1655 */
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08001656 @GuardedBy("mMethodMap")
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08001657 private boolean calledWithValidTokenLocked(@NonNull IBinder token) {
1658 if (token == null) {
1659 throw new InvalidParameterException("token must not be null.");
Yohei Yukawad0332832017-02-01 13:59:43 -08001660 }
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08001661 if (token != mCurToken) {
Yohei Yukawad0332832017-02-01 13:59:43 -08001662 Slog.e(TAG, "Ignoring " + Debug.getCaller() + " due to an invalid token."
1663 + " uid:" + Binder.getCallingUid() + " token:" + token);
Yohei Yukawa22c97be2014-06-04 19:43:36 +09001664 return false;
1665 }
1666 return true;
1667 }
1668
Yohei Yukawaf80087c2018-05-21 09:47:53 -07001669 @GuardedBy("mMethodMap")
1670 private boolean bindCurrentInputMethodServiceLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001671 Intent service, ServiceConnection conn, int flags) {
1672 if (service == null || conn == null) {
1673 Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn);
1674 return false;
1675 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08001676 return mContext.bindServiceAsUser(service, conn, flags,
1677 new UserHandle(mSettings.getCurrentUserId()));
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001678 }
1679
satoke7c6998e2011-06-03 17:57:59 +09001680 @Override
Yohei Yukawad20eef82019-02-05 10:45:32 -08001681 public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
1682 if (UserHandle.getCallingUserId() != userId) {
1683 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
1684 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001685 synchronized (mMethodMap) {
Yohei Yukawad20eef82019-02-05 10:45:32 -08001686 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001687 mSettings.getCurrentUserId(), null);
1688 if (resolvedUserIds.length != 1) {
1689 return Collections.emptyList();
1690 }
1691 final long ident = Binder.clearCallingIdentity();
1692 try {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08001693 return getInputMethodListLocked(resolvedUserIds[0]);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001694 } finally {
1695 Binder.restoreCallingIdentity(ident);
Tarandeep Singh89a6c482017-11-21 14:26:11 -08001696 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 }
1698 }
1699
satoke7c6998e2011-06-03 17:57:59 +09001700 @Override
Yohei Yukawa1fb13c52019-02-05 07:55:28 -08001701 public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
1702 if (UserHandle.getCallingUserId() != userId) {
1703 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
1704 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001705 synchronized (mMethodMap) {
Yohei Yukawa1fb13c52019-02-05 07:55:28 -08001706 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001707 mSettings.getCurrentUserId(), null);
1708 if (resolvedUserIds.length != 1) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001709 return Collections.emptyList();
1710 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001711 final long ident = Binder.clearCallingIdentity();
1712 try {
1713 return getEnabledInputMethodListLocked(resolvedUserIds[0]);
1714 } finally {
1715 Binder.restoreCallingIdentity(ident);
1716 }
1717 }
1718 }
1719
1720 @GuardedBy("mMethodMap")
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08001721 private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001722 final ArrayList<InputMethodInfo> methodList;
1723 if (userId == mSettings.getCurrentUserId()) {
1724 // Create a copy.
1725 methodList = new ArrayList<>(mMethodList);
1726 } else {
1727 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1728 methodList = new ArrayList<>();
1729 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1730 new ArrayMap<>();
1731 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1732 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1733 methodList);
1734 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001735 return methodList;
1736 }
1737
1738 @GuardedBy("mMethodMap")
1739 private List<InputMethodInfo> getEnabledInputMethodListLocked(@UserIdInt int userId) {
1740 if (userId == mSettings.getCurrentUserId()) {
satokd87c2592010-09-29 11:52:06 +09001741 return mSettings.getEnabledInputMethodListLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001743 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1744 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
1745 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1746 new ArrayMap<>();
1747 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1748 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1749 methodList);
1750 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
Yohei Yukawaf9277532019-01-25 02:47:32 -08001751 mContext.getContentResolver(), methodMap, userId, true);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001752 return settings.getEnabledInputMethodListLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 }
1754
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001755 /**
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001756 * @param imiId if null, returns enabled subtypes for the current imi
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001757 * @return enabled subtypes of the specified imi
1758 */
satoke7c6998e2011-06-03 17:57:59 +09001759 @Override
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001760 public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
satok16331c82010-12-20 23:48:46 +09001761 boolean allowsImplicitlySelectedSubtypes) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001762 final int callingUserId = UserHandle.getCallingUserId();
satok67ddf9c2010-11-17 09:45:54 +09001763 synchronized (mMethodMap) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001764 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
1765 mSettings.getCurrentUserId(), null);
1766 if (resolvedUserIds.length != 1) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001767 return Collections.emptyList();
1768 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001769 final long ident = Binder.clearCallingIdentity();
1770 try {
1771 return getEnabledInputMethodSubtypeListLocked(imiId,
1772 allowsImplicitlySelectedSubtypes, resolvedUserIds[0]);
1773 } finally {
1774 Binder.restoreCallingIdentity(ident);
1775 }
1776 }
1777 }
1778
1779 @GuardedBy("mMethodMap")
1780 private List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(String imiId,
1781 boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) {
1782 if (userId == mSettings.getCurrentUserId()) {
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001783 final InputMethodInfo imi;
1784 if (imiId == null && mCurMethodId != null) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001785 imi = mMethodMap.get(mCurMethodId);
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001786 } else {
1787 imi = mMethodMap.get(imiId);
1788 }
1789 if (imi == null) {
Yohei Yukawab0377bb2015-08-10 21:06:30 -07001790 return Collections.emptyList();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001791 }
1792 return mSettings.getEnabledInputMethodSubtypeListLocked(
1793 mContext, imi, allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +09001794 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001795 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1796 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
1797 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1798 new ArrayMap<>();
1799 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1800 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1801 methodList);
1802 final InputMethodInfo imi = methodMap.get(imiId);
1803 if (imi == null) {
1804 return Collections.emptyList();
1805 }
1806 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
Yohei Yukawaf9277532019-01-25 02:47:32 -08001807 mContext.getContentResolver(), methodMap, userId, true);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001808 return settings.getEnabledInputMethodSubtypeListLocked(
1809 mContext, imi, allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +09001810 }
1811
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001812 /**
1813 * Called by each application process as a preparation to start interacting with
1814 * {@link InputMethodManagerService}.
1815 *
1816 * <p>As a general principle, IPCs from the application process that take
Yohei Yukawa499e3f72018-10-21 20:15:11 -07001817 * {@link IInputMethodClient} will be rejected without this step.</p>
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001818 *
1819 * @param client {@link android.os.Binder} proxy that is associated with the singleton instance
1820 * of {@link android.view.inputmethod.InputMethodManager} that runs on the client
1821 * process
1822 * @param inputContext communication channel for the dummy
1823 * {@link android.view.inputmethod.InputConnection}
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001824 * @param selfReportedDisplayId self-reported display ID to which the client is associated.
1825 * Whether the client is still allowed to access to this display
1826 * or not needs to be evaluated every time the client interacts
1827 * with the display
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001828 */
1829 @Override
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001830 public void addClient(IInputMethodClient client, IInputContext inputContext,
1831 int selfReportedDisplayId) {
Yohei Yukawacb768bc2018-10-24 16:05:09 -07001832 // Here there are two scenarios where this method is called:
1833 // A. IMM is being instantiated in a different process and this is an IPC from that process
1834 // B. IMM is being instantiated in the same process but Binder.clearCallingIdentity() is
1835 // called in the caller side if necessary.
1836 // In either case the following UID/PID should be the ones where InputMethodManager is
1837 // actually running.
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001838 final int callerUid = Binder.getCallingUid();
1839 final int callerPid = Binder.getCallingPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001840 synchronized (mMethodMap) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001841 // TODO: Optimize this linear search.
Yohei Yukawaac9311e2018-11-20 19:25:23 -08001842 final int numClients = mClients.size();
1843 for (int i = 0; i < numClients; ++i) {
1844 final ClientState state = mClients.valueAt(i);
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001845 if (state.uid == callerUid && state.pid == callerPid
1846 && state.selfReportedDisplayId == selfReportedDisplayId) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001847 throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
Yohei Yukawacb768bc2018-10-24 16:05:09 -07001848 + "/displayId=" + selfReportedDisplayId + " is already registered.");
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001849 }
1850 }
1851 final ClientDeathRecipient deathRecipient = new ClientDeathRecipient(this, client);
1852 try {
1853 client.asBinder().linkToDeath(deathRecipient, 0);
1854 } catch (RemoteException e) {
1855 throw new IllegalStateException(e);
1856 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001857 // We cannot fully avoid race conditions where the client UID already lost the access to
1858 // the given self-reported display ID, even if the client is not maliciously reporting
1859 // a fake display ID. Unconditionally returning SecurityException just because the
1860 // client doesn't pass display ID verification can cause many test failures hence not an
1861 // option right now. At the same time
1862 // context.getSystemService(InputMethodManager.class)
1863 // is expected to return a valid non-null instance at any time if we do not choose to
1864 // have the client crash. Thus we do not verify the display ID at all here. Instead we
1865 // later check the display ID every time the client needs to interact with the specified
1866 // display.
1867 mClients.put(client.asBinder(), new ClientState(client, inputContext, callerUid,
1868 callerPid, selfReportedDisplayId, deathRecipient));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869 }
1870 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001871
Yohei Yukawae24ed792018-08-28 19:10:32 -07001872 void removeClient(IInputMethodClient client) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001873 synchronized (mMethodMap) {
Jeff Brownc28867a2013-03-26 15:42:39 -07001874 ClientState cs = mClients.remove(client.asBinder());
1875 if (cs != null) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001876 client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
Jeff Brownc28867a2013-03-26 15:42:39 -07001877 clearClientSessionLocked(cs);
Yohei Yukawa072b1b52015-11-18 15:54:34 -08001878 if (mCurClient == cs) {
Tarandeep Singh93c00cea2018-02-16 14:31:17 -08001879 if (mBoundToMethod) {
1880 mBoundToMethod = false;
1881 if (mCurMethod != null) {
1882 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
1883 MSG_UNBIND_INPUT, mCurMethod));
1884 }
1885 }
Yohei Yukawa072b1b52015-11-18 15:54:34 -08001886 mCurClient = null;
1887 }
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08001888 if (mCurFocusedWindowClient == cs) {
1889 mCurFocusedWindowClient = null;
1890 }
Jeff Brownc28867a2013-03-26 15:42:39 -07001891 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001892 }
1893 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001894
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001895 void executeOrSendMessage(IInterface target, Message msg) {
1896 if (target.asBinder() instanceof Binder) {
1897 mCaller.sendMessage(msg);
1898 } else {
1899 handleMessage(msg);
1900 msg.recycle();
1901 }
1902 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001903
Yohei Yukawa4afd9332018-10-21 10:43:53 -07001904 void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001905 if (mCurClient != null) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001906 if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001907 + mCurClient.client.asBinder());
1908 if (mBoundToMethod) {
1909 mBoundToMethod = false;
1910 if (mCurMethod != null) {
1911 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
1912 MSG_UNBIND_INPUT, mCurMethod));
1913 }
1914 }
Dianne Hackborna6e41342012-05-22 16:30:34 -07001915
Yohei Yukawa2bc66172017-02-08 11:13:25 -08001916 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
1917 MSG_SET_ACTIVE, 0, 0, mCurClient));
Yohei Yukawa33e81792015-11-17 21:14:42 -08001918 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
1919 MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001920 mCurClient.sessionRequested = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001921 mCurClient = null;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001922
The Android Open Source Project10592532009-03-18 17:39:46 -07001923 hideInputMethodMenuLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 }
1925 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001926
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001927 private int getImeShowFlags() {
1928 int flags = 0;
1929 if (mShowForced) {
1930 flags |= InputMethod.SHOW_FORCED
1931 | InputMethod.SHOW_EXPLICIT;
1932 } else if (mShowExplicitlyRequested) {
1933 flags |= InputMethod.SHOW_EXPLICIT;
1934 }
1935 return flags;
1936 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001937
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001938 private int getAppShowFlags() {
1939 int flags = 0;
1940 if (mShowForced) {
1941 flags |= InputMethodManager.SHOW_FORCED;
1942 } else if (!mShowExplicitlyRequested) {
1943 flags |= InputMethodManager.SHOW_IMPLICIT;
1944 }
1945 return flags;
1946 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001947
Andreas Gampea36dc622018-02-05 17:19:22 -08001948 @GuardedBy("mMethodMap")
Yohei Yukawa2553e482017-12-15 15:47:33 -08001949 @NonNull
Yohei Yukawadc66e522018-10-21 10:43:14 -07001950 InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001951 if (!mBoundToMethod) {
1952 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
1953 MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
1954 mBoundToMethod = true;
1955 }
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08001956
1957 final Binder startInputToken = new Binder();
Yohei Yukawa7979e1a2019-02-12 02:01:10 -08001958 final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), mCurToken,
1959 mCurTokenDisplayId, mCurId, startInputReason, !initial,
1960 UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId,
1961 mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, mCurSeq);
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07001962 mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
Yohei Yukawa357b2f62017-02-14 09:40:03 -08001963 mStartInputHistory.addEntry(info);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08001964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965 final SessionState session = mCurClient.curSession;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08001966 executeOrSendMessage(session.method, mCaller.obtainMessageIIOOOO(
Yohei Yukawaf7526b52017-02-11 20:57:10 -08001967 MSG_START_INPUT, mCurInputContextMissingMethods, initial ? 0 : 1 /* restarting */,
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08001968 startInputToken, session, mCurInputContext, mCurAttribute));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 if (mShowRequested) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001970 if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
The Android Open Source Project4df24232009-03-05 14:34:35 -08001971 showCurrentInputLocked(getAppShowFlags(), null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001972 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08001973 return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
1974 session.session, (session.channel != null ? session.channel.dup() : null),
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07001975 mCurId, mCurSeq);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001977
Andreas Gampea36dc622018-02-05 17:19:22 -08001978 @GuardedBy("mMethodMap")
Yohei Yukawa2553e482017-12-15 15:47:33 -08001979 @NonNull
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001980 InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07001981 @MissingMethodFlags int missingMethods, @NonNull EditorInfo attribute,
1982 @StartInputFlags int startInputFlags, @StartInputReason int startInputReason) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08001983 // If no method is currently selected, do nothing.
1984 if (mCurMethodId == null) {
Yohei Yukawa2553e482017-12-15 15:47:33 -08001985 return InputBindResult.NO_IME;
Dianne Hackborn7663d802012-02-24 13:08:49 -08001986 }
1987
Yohei Yukawa0deaef02018-10-17 10:33:48 +08001988 if (!mSystemReady) {
1989 // If the system is not yet ready, we shouldn't be running third
1990 // party code.
1991 return new InputBindResult(
1992 InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
1993 null, null, mCurMethodId, mCurSeq);
1994 }
1995
Yohei Yukawad57ba672015-06-08 16:39:46 -07001996 if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
1997 attribute.packageName)) {
1998 Slog.e(TAG, "Rejecting this client as it reported an invalid package name."
1999 + " uid=" + cs.uid + " package=" + attribute.packageName);
Yohei Yukawa2553e482017-12-15 15:47:33 -08002000 return InputBindResult.INVALID_PACKAGE_NAME;
Yohei Yukawa0f3ad12015-04-06 16:48:24 -07002001 }
2002
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002003 if (!mWindowManagerInternal.isUidAllowedOnDisplay(cs.selfReportedDisplayId, cs.uid)) {
2004 // Wait, the client no longer has access to the display.
2005 return InputBindResult.INVALID_DISPLAY_ID;
2006 }
lumarkef1965b2018-09-12 17:42:53 +08002007 // Compute the final shown display ID with validated cs.selfReportedDisplayId for this
2008 // session & other conditions.
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08002009 final int displayIdToShowIme = computeImeDisplayIdForTarget(cs.selfReportedDisplayId,
2010 mImeDisplayValidator);
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002012 if (mCurClient != cs) {
John Spurlocke0980502013-10-25 11:59:29 -04002013 // Was the keyguard locked when switching over to the new client?
2014 mCurClientInKeyguard = isKeyguardLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002015 // If the client is changing, we need to switch over to the new
2016 // one.
Yohei Yukawab7526452018-10-21 20:15:17 -07002017 unbindCurrentClientLocked(UnbindReason.SWITCH_CLIENT);
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002018 if (DEBUG) Slog.v(TAG, "switching to client: client="
John Spurlocke0980502013-10-25 11:59:29 -04002019 + cs.client.asBinder() + " keyguard=" + mCurClientInKeyguard);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020
2021 // If the screen is on, inform the new client it is active
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07002022 if (mIsInteractive) {
tiansiming [田思明]e102c972018-04-17 18:15:33 +08002023 executeOrSendMessage(cs.client, mCaller.obtainMessageIO(MSG_SET_ACTIVE, 1, cs));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024 }
2025 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002026
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002027 // Bump up the sequence for this client and attach it.
2028 mCurSeq++;
2029 if (mCurSeq <= 0) mCurSeq = 1;
2030 mCurClient = cs;
2031 mCurInputContext = inputContext;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07002032 mCurInputContextMissingMethods = missingMethods;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002033 mCurAttribute = attribute;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002035 // Check if the input method is changing.
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002036 // We expect the caller has already verified that the client is allowed to access this
2037 // display ID.
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002038 if (mCurId != null && mCurId.equals(mCurMethodId)
2039 && displayIdToShowIme == mCurTokenDisplayId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002040 if (cs.curSession != null) {
2041 // Fast case: if we are already connected to the input method,
2042 // then just return it.
Yohei Yukawa87ca8402017-02-07 00:13:14 -08002043 return attachNewInputLocked(startInputReason,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002044 (startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002045 }
2046 if (mHaveConnection) {
2047 if (mCurMethod != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002048 // Return to client, and we will get back with it when
2049 // we have had a session made for it.
Jeff Brownc28867a2013-03-26 15:42:39 -07002050 requestClientSessionLocked(cs);
Yohei Yukawa2553e482017-12-15 15:47:33 -08002051 return new InputBindResult(
2052 InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07002053 null, null, mCurId, mCurSeq);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 } else if (SystemClock.uptimeMillis()
2055 < (mLastBindTime+TIME_TO_RECONNECT)) {
2056 // In this case we have connected to the service, but
2057 // don't yet have its interface. If it hasn't been too
2058 // long since we did the connection, we'll return to
2059 // the client and wait to get the service interface so
2060 // we can report back. If it has been too long, we want
2061 // to fall through so we can try a disconnect/reconnect
2062 // to see if we can get back in touch with the service.
Yohei Yukawa2553e482017-12-15 15:47:33 -08002063 return new InputBindResult(
2064 InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07002065 null, null, mCurId, mCurSeq);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 } else {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002067 EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
2068 mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002069 }
2070 }
2071 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002072
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 InputMethodInfo info = mMethodMap.get(mCurMethodId);
2074 if (info == null) {
2075 throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
2076 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002077
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002078 unbindCurrentMethodLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002080 mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
2081 mCurIntent.setComponent(info.getComponent());
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07002082 mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
2083 com.android.internal.R.string.input_method_binding_label);
2084 mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
2085 mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002086
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002087 if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002088 mLastBindTime = SystemClock.uptimeMillis();
2089 mHaveConnection = true;
2090 mCurId = info.getId();
2091 mCurToken = new Binder();
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002092 mCurTokenDisplayId = displayIdToShowIme;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002093 try {
lumark90120a82018-08-15 00:33:03 +08002094 if (DEBUG) {
2095 Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
2096 + mCurTokenDisplayId);
2097 }
Yohei Yukawa6e875592019-01-28 00:49:30 -08002098 mIWindowManager.addWindowToken(mCurToken, LayoutParams.TYPE_INPUT_METHOD,
2099 mCurTokenDisplayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002100 } catch (RemoteException e) {
2101 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002102 return new InputBindResult(
2103 InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07002104 null, null, mCurId, mCurSeq);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002105 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002106 mCurIntent = null;
2107 Slog.w(TAG, "Failure connecting to input method service: " + mCurIntent);
2108 return InputBindResult.IME_NOT_CONNECTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002109 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002110
lumarkef1965b2018-09-12 17:42:53 +08002111 @FunctionalInterface
2112 interface ImeDisplayValidator {
2113 boolean displayCanShowIme(int displayId);
2114 }
2115
2116 /**
2117 * Find the display where the IME should be shown.
2118 *
2119 * @param displayId the ID of the display where the IME client target is.
lumarkef1965b2018-09-12 17:42:53 +08002120 * @param checker instance of {@link ImeDisplayValidator} which is used for
2121 * checking display config to adjust the final target display.
2122 * @return The ID of the display where the IME should be shown.
2123 */
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08002124 static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
lumarkef1965b2018-09-12 17:42:53 +08002125 if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
2126 // We always assume that the default display id suitable to show the IME window.
2127 return DEFAULT_DISPLAY;
2128 }
2129 // Show IME in default display when the display with IME target doesn't support system
2130 // decorations.
2131 return checker.displayCanShowIme(displayId) ? displayId : DEFAULT_DISPLAY;
2132 }
2133
satoke7c6998e2011-06-03 17:57:59 +09002134 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002135 public void onServiceConnected(ComponentName name, IBinder service) {
2136 synchronized (mMethodMap) {
2137 if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
2138 mCurMethod = IInputMethod.Stub.asInterface(service);
Dianne Hackborncc278702009-09-02 23:07:23 -07002139 if (mCurToken == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002140 Slog.w(TAG, "Service connected without a token!");
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002141 unbindCurrentMethodLocked();
Dianne Hackborncc278702009-09-02 23:07:23 -07002142 return;
2143 }
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002144 if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
lumark90120a82018-08-15 00:33:03 +08002145 // Dispatch display id for InputMethodService to update context display.
2146 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
2147 MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002148 if (mCurClient != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002149 clearClientSessionLocked(mCurClient);
2150 requestClientSessionLocked(mCurClient);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002151 }
2152 }
2153 }
2154 }
2155
Jeff Brownc28867a2013-03-26 15:42:39 -07002156 void onSessionCreated(IInputMethod method, IInputMethodSession session,
2157 InputChannel channel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002158 synchronized (mMethodMap) {
2159 if (mCurMethod != null && method != null
2160 && mCurMethod.asBinder() == method.asBinder()) {
2161 if (mCurClient != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002162 clearClientSessionLocked(mCurClient);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002163 mCurClient.curSession = new SessionState(mCurClient,
Jeff Brownc28867a2013-03-26 15:42:39 -07002164 method, session, channel);
Yohei Yukawa87ca8402017-02-07 00:13:14 -08002165 InputBindResult res = attachNewInputLocked(
Yohei Yukawa42194222018-10-21 20:14:40 -07002166 StartInputReason.SESSION_CREATED_BY_IME, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167 if (res.method != null) {
2168 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
Yohei Yukawa33e81792015-11-17 21:14:42 -08002169 MSG_BIND_CLIENT, mCurClient.client, res));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002170 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002171 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002172 }
2173 }
2174 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002175
2176 // Session abandoned. Close its associated input channel.
2177 channel.dispose();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002178 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002179
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002180 void unbindCurrentMethodLocked() {
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002181 if (mVisibleBound) {
2182 mContext.unbindService(mVisibleConnection);
2183 mVisibleBound = false;
2184 }
2185
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002186 if (mHaveConnection) {
2187 mContext.unbindService(this);
2188 mHaveConnection = false;
2189 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002190
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002191 if (mCurToken != null) {
2192 try {
lumark90120a82018-08-15 00:33:03 +08002193 if (DEBUG) {
2194 Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
2195 + mCurTokenDisplayId);
2196 }
lumark90120a82018-08-15 00:33:03 +08002197 mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002198 } catch (RemoteException e) {
2199 }
2200 mCurToken = null;
lumark90120a82018-08-15 00:33:03 +08002201 mCurTokenDisplayId = INVALID_DISPLAY;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002202 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002203
The Android Open Source Project10592532009-03-18 17:39:46 -07002204 mCurId = null;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002205 clearCurMethodLocked();
Yohei Yukawabc7b5262015-11-17 17:38:41 -08002206 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002207
Yohei Yukawa4afd9332018-10-21 10:43:53 -07002208 void resetCurrentMethodAndClient(@UnbindReason int unbindClientReason) {
Yohei Yukawabc7b5262015-11-17 17:38:41 -08002209 mCurMethodId = null;
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002210 unbindCurrentMethodLocked();
Yohei Yukawa33e81792015-11-17 21:14:42 -08002211 unbindCurrentClientLocked(unbindClientReason);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002212 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002213
2214 void requestClientSessionLocked(ClientState cs) {
2215 if (!cs.sessionRequested) {
2216 if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
2217 InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString());
2218 cs.sessionRequested = true;
2219 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOOO(
2220 MSG_CREATE_SESSION, mCurMethod, channels[1],
2221 new MethodCallback(this, mCurMethod, channels[0])));
2222 }
2223 }
2224
2225 void clearClientSessionLocked(ClientState cs) {
2226 finishSessionLocked(cs.curSession);
2227 cs.curSession = null;
2228 cs.sessionRequested = false;
2229 }
2230
2231 private void finishSessionLocked(SessionState sessionState) {
2232 if (sessionState != null) {
2233 if (sessionState.session != null) {
2234 try {
2235 sessionState.session.finishSession();
2236 } catch (RemoteException e) {
2237 Slog.w(TAG, "Session failed to close due to remote exception", e);
Yohei Yukawa849443c2019-01-21 09:02:25 -08002238 updateSystemUiLocked(0 /* vis */, mBackDisposition);
Jeff Brownc28867a2013-03-26 15:42:39 -07002239 }
2240 sessionState.session = null;
2241 }
2242 if (sessionState.channel != null) {
2243 sessionState.channel.dispose();
2244 sessionState.channel = null;
Devin Taylor0c33ed22010-02-23 13:26:46 -06002245 }
2246 }
2247 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002248
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002249 void clearCurMethodLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002250 if (mCurMethod != null) {
Yohei Yukawaac9311e2018-11-20 19:25:23 -08002251 final int numClients = mClients.size();
2252 for (int i = 0; i < numClients; ++i) {
2253 clearClientSessionLocked(mClients.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002254 }
Devin Taylor0c33ed22010-02-23 13:26:46 -06002255
Jeff Brownc28867a2013-03-26 15:42:39 -07002256 finishSessionLocked(mEnabledSession);
Devin Taylor0c33ed22010-02-23 13:26:46 -06002257 mEnabledSession = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002258 mCurMethod = null;
2259 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002260 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002261 mStatusBar.setIconVisibility(mSlotIme, false);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002262 }
Yohei Yukawa2bc66172017-02-08 11:13:25 -08002263 mInFullscreenMode = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002264 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002265
satoke7c6998e2011-06-03 17:57:59 +09002266 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002267 public void onServiceDisconnected(ComponentName name) {
Yohei Yukawa817d5f72017-01-04 20:15:02 -08002268 // Note that mContext.unbindService(this) does not trigger this. Hence if we are here the
2269 // disconnection is not intended by IMMS (e.g. triggered because the current IMS crashed),
2270 // which is irregular but can eventually happen for everyone just by continuing using the
2271 // device. Thus it is important to make sure that all the internal states are properly
2272 // refreshed when this method is called back. Running
2273 // adb install -r <APK that implements the current IME>
2274 // would be a good way to trigger such a situation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002275 synchronized (mMethodMap) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002276 if (DEBUG) Slog.v(TAG, "Service disconnected: " + name
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002277 + " mCurIntent=" + mCurIntent);
2278 if (mCurMethod != null && mCurIntent != null
2279 && name.equals(mCurIntent.getComponent())) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002280 clearCurMethodLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002281 // We consider this to be a new bind attempt, since the system
2282 // should now try to restart the service for us.
2283 mLastBindTime = SystemClock.uptimeMillis();
2284 mShowRequested = mInputShown;
2285 mInputShown = false;
Yohei Yukawab7526452018-10-21 20:15:17 -07002286 unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002287 }
2288 }
2289 }
2290
Yohei Yukawaeec552e2018-09-09 20:48:41 -07002291 @BinderThread
Yohei Yukawa41b094f2018-09-09 23:58:45 -07002292 private void updateStatusIcon(@NonNull IBinder token, String packageName,
2293 @DrawableRes int iconId) {
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002294 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002295 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002296 return;
2297 }
2298 final long ident = Binder.clearCallingIdentity();
2299 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 if (iconId == 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002301 if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
Dianne Hackborn661cd522011-08-22 00:26:20 -07002302 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002303 mStatusBar.setIconVisibility(mSlotIme, false);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002304 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002305 } else if (packageName != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002306 if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002307 CharSequence contentDescription = null;
2308 try {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002309 // Use PackageManager to load label
2310 final PackageManager packageManager = mContext.getPackageManager();
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002311 contentDescription = packageManager.getApplicationLabel(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002312 mIPackageManager.getApplicationInfo(packageName, 0,
2313 mSettings.getCurrentUserId()));
2314 } catch (RemoteException e) {
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002315 /* ignore */
2316 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002317 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002318 mStatusBar.setIcon(mSlotIme, packageName, iconId, 0,
Dianne Hackborn661cd522011-08-22 00:26:20 -07002319 contentDescription != null
2320 ? contentDescription.toString() : null);
Jason Monk3e189872016-01-12 09:10:34 -05002321 mStatusBar.setIconVisibility(mSlotIme, true);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002322 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002323 }
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002324 } finally {
2325 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002326 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002327 }
2328 }
2329
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002330 private boolean shouldShowImeSwitcherLocked(int visibility) {
satok7cfc0ed2011-06-20 21:29:36 +09002331 if (!mShowOngoingImeSwitcherForPhones) return false;
Jason Monk807ef762014-05-08 15:47:46 -04002332 if (mSwitchingDialog != null) return false;
Yohei Yukawad2bc3092017-07-31 15:37:14 -07002333 if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
2334 && mKeyguardManager != null && mKeyguardManager.isKeyguardSecure()) return false;
Tarandeep Singheadb1392018-11-09 18:15:57 +01002335 if ((visibility & InputMethodService.IME_ACTIVE) == 0
2336 || (visibility & InputMethodService.IME_INVISIBLE) != 0) {
2337 return false;
2338 }
Seigo Nonaka7309b122015-08-17 18:34:13 -07002339 if (mWindowManagerInternal.isHardKeyboardAvailable()) {
Yohei Yukawafa0e47e2016-04-05 09:55:56 -07002340 if (mHardKeyboardBehavior == HardKeyboardBehavior.WIRELESS_AFFORDANCE) {
2341 // When physical keyboard is attached, we show the ime switcher (or notification if
2342 // NavBar is not available) because SHOW_IME_WITH_HARD_KEYBOARD settings currently
2343 // exists in the IME switcher dialog. Might be OK to remove this condition once
2344 // SHOW_IME_WITH_HARD_KEYBOARD settings finds a good place to live.
2345 return true;
2346 }
Yohei Yukawa89398382016-03-29 11:37:04 -07002347 } else if ((visibility & InputMethodService.IME_VISIBLE) == 0) {
2348 return false;
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002349 }
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002350
2351 List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
2352 final int N = imis.size();
2353 if (N > 2) return true;
2354 if (N < 1) return false;
2355 int nonAuxCount = 0;
2356 int auxCount = 0;
2357 InputMethodSubtype nonAuxSubtype = null;
2358 InputMethodSubtype auxSubtype = null;
2359 for(int i = 0; i < N; ++i) {
2360 final InputMethodInfo imi = imis.get(i);
2361 final List<InputMethodSubtype> subtypes =
2362 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
2363 final int subtypeCount = subtypes.size();
2364 if (subtypeCount == 0) {
2365 ++nonAuxCount;
2366 } else {
2367 for (int j = 0; j < subtypeCount; ++j) {
2368 final InputMethodSubtype subtype = subtypes.get(j);
2369 if (!subtype.isAuxiliary()) {
2370 ++nonAuxCount;
2371 nonAuxSubtype = subtype;
2372 } else {
2373 ++auxCount;
2374 auxSubtype = subtype;
satok7cfc0ed2011-06-20 21:29:36 +09002375 }
2376 }
satok7cfc0ed2011-06-20 21:29:36 +09002377 }
2378 }
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002379 if (nonAuxCount > 1 || auxCount > 1) {
2380 return true;
2381 } else if (nonAuxCount == 1 && auxCount == 1) {
2382 if (nonAuxSubtype != null && auxSubtype != null
2383 && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
2384 || auxSubtype.overridesImplicitlyEnabledSubtype()
2385 || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
2386 && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
2387 return false;
2388 }
2389 return true;
2390 }
2391 return false;
satok7cfc0ed2011-06-20 21:29:36 +09002392 }
2393
John Spurlocke0980502013-10-25 11:59:29 -04002394 private boolean isKeyguardLocked() {
2395 return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
2396 }
2397
Yohei Yukawad6475a62017-04-17 10:35:27 -07002398 @BinderThread
satokdbf29502011-08-25 15:28:23 +09002399 @SuppressWarnings("deprecation")
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08002400 private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002401 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002402 if (!calledWithValidTokenLocked(token)) {
2403 return;
2404 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002405 mImeWindowVis = vis;
2406 mBackDisposition = backDisposition;
Yohei Yukawa849443c2019-01-21 09:02:25 -08002407 updateSystemUiLocked(vis, backDisposition);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002408 }
Yohei Yukawad6475a62017-04-17 10:35:27 -07002409
2410 final boolean dismissImeOnBackKeyPressed;
2411 switch (backDisposition) {
2412 case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
2413 dismissImeOnBackKeyPressed = true;
2414 break;
2415 case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
2416 dismissImeOnBackKeyPressed = false;
2417 break;
2418 default:
2419 case InputMethodService.BACK_DISPOSITION_DEFAULT:
2420 dismissImeOnBackKeyPressed = ((vis & InputMethodService.IME_VISIBLE) != 0);
2421 break;
2422 }
Yohei Yukawaee2a7ed2017-02-15 21:38:57 -08002423 mWindowManagerInternal.updateInputMethodWindowStatus(token,
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002424 (vis & InputMethodService.IME_VISIBLE) != 0, dismissImeOnBackKeyPressed);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002425 }
2426
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002427 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08002428 private void reportStartInput(@NonNull IBinder token, IBinder startInputToken) {
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002429 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002430 if (!calledWithValidTokenLocked(token)) {
2431 return;
2432 }
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002433 final IBinder targetWindow = mImeTargetWindowMap.get(startInputToken);
2434 if (targetWindow != null && mLastImeTargetWindow != targetWindow) {
2435 mWindowManagerInternal.updateInputMethodTargetWindow(token, targetWindow);
2436 }
2437 mLastImeTargetWindow = targetWindow;
2438 }
2439 }
2440
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002441 // Caution! This method is called in this class. Handle multi-user carefully
Yohei Yukawa849443c2019-01-21 09:02:25 -08002442 private void updateSystemUiLocked(int vis, int backDisposition) {
2443 if (mCurToken == null) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002444 return;
2445 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01002446 if (DEBUG) {
2447 Slog.d(TAG, "IME window vis: " + vis
2448 + " active: " + (vis & InputMethodService.IME_ACTIVE)
2449 + " inv: " + (vis & InputMethodService.IME_INVISIBLE));
2450 }
2451
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002452 // TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
2453 // all updateSystemUi happens on system previlege.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002454 final long ident = Binder.clearCallingIdentity();
satok06487a52010-10-29 11:37:18 +09002455 try {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002456 // apply policy for binder calls
2457 if (vis != 0 && isKeyguardLocked() && !mCurClientInKeyguard) {
2458 vis = 0;
satok06487a52010-10-29 11:37:18 +09002459 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002460 // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
2461 final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
2462 if (mStatusBar != null) {
Yohei Yukawa849443c2019-01-21 09:02:25 -08002463 mStatusBar.setImeWindowStatus(mCurToken, vis, backDisposition,
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002464 needsToShowImeSwitcher);
2465 }
2466 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
2467 if (imi != null && needsToShowImeSwitcher) {
2468 // Used to load label
2469 final CharSequence title = mRes.getText(
2470 com.android.internal.R.string.select_input_method);
2471 final CharSequence summary = InputMethodUtils.getImeAndSubtypeDisplayName(
2472 mContext, imi, mCurrentSubtype);
Chris Wren1ce4b6d2015-06-11 10:19:43 -04002473 mImeSwitcherNotification.setContentTitle(title)
2474 .setContentText(summary)
2475 .setContentIntent(mImeSwitchPendingIntent);
Seigo Nonaka7309b122015-08-17 18:34:13 -07002476 try {
Charles Chenea6e7f02018-11-19 21:37:45 +08002477 // TODO(b/120076400): Figure out what is the best behavior
Seigo Nonaka7309b122015-08-17 18:34:13 -07002478 if ((mNotificationManager != null)
Charles Chenea6e7f02018-11-19 21:37:45 +08002479 && !mIWindowManager.hasNavigationBar(DEFAULT_DISPLAY)) {
Seigo Nonaka7309b122015-08-17 18:34:13 -07002480 if (DEBUG) {
2481 Slog.d(TAG, "--- show notification: label = " + summary);
2482 }
2483 mNotificationManager.notifyAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04002484 SystemMessage.NOTE_SELECT_INPUT_METHOD,
Seigo Nonaka7309b122015-08-17 18:34:13 -07002485 mImeSwitcherNotification.build(), UserHandle.ALL);
2486 mNotificationShown = true;
Dianne Hackborn661cd522011-08-22 00:26:20 -07002487 }
Seigo Nonaka7309b122015-08-17 18:34:13 -07002488 } catch (RemoteException e) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002489 }
2490 } else {
2491 if (mNotificationShown && mNotificationManager != null) {
2492 if (DEBUG) {
2493 Slog.d(TAG, "--- hide notification");
satok7cfc0ed2011-06-20 21:29:36 +09002494 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002495 mNotificationManager.cancelAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04002496 SystemMessage.NOTE_SELECT_INPUT_METHOD, UserHandle.ALL);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002497 mNotificationShown = false;
satok7cfc0ed2011-06-20 21:29:36 +09002498 }
satok06487a52010-10-29 11:37:18 +09002499 }
2500 } finally {
2501 Binder.restoreCallingIdentity(ident);
2502 }
2503 }
2504
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002505 void updateFromSettingsLocked(boolean enabledMayChange) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07002506 updateInputMethodsFromSettingsLocked(enabledMayChange);
2507 updateKeyboardFromSettingsLocked();
2508 }
2509
2510 void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002511 if (enabledMayChange) {
2512 List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
2513 for (int i=0; i<enabled.size(); i++) {
2514 // We allow the user to select "disabled until used" apps, so if they
2515 // are enabling one of those here we now need to make it enabled.
2516 InputMethodInfo imm = enabled.get(i);
2517 try {
2518 ApplicationInfo ai = mIPackageManager.getApplicationInfo(imm.getPackageName(),
2519 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
2520 mSettings.getCurrentUserId());
Satoshi Kataoka7987a312013-04-17 18:59:33 +09002521 if (ai != null && ai.enabledSetting
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002522 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09002523 if (DEBUG) {
2524 Slog.d(TAG, "Update state(" + imm.getId()
2525 + "): DISABLED_UNTIL_USED -> DEFAULT");
2526 }
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002527 mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
2528 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
Dianne Hackborn3fa3c28a2013-03-26 16:15:41 -07002529 PackageManager.DONT_KILL_APP, mSettings.getCurrentUserId(),
2530 mContext.getBasePackageName());
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002531 }
2532 } catch (RemoteException e) {
2533 }
2534 }
2535 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002536 // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and
2537 // ENABLED_INPUT_METHODS is taking care of keeping them correctly in
2538 // sync, so we will never have a DEFAULT_INPUT_METHOD that is not
2539 // enabled.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002540 String id = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09002541 // There is no input method selected, try to choose new applicable input method.
2542 if (TextUtils.isEmpty(id) && chooseNewDefaultIMELocked()) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002543 id = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09002544 }
2545 if (!TextUtils.isEmpty(id)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002546 try {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09002547 setInputMethodLocked(id, mSettings.getSelectedInputMethodSubtypeId(id));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002548 } catch (IllegalArgumentException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002549 Slog.w(TAG, "Unknown input method from prefs: " + id, e);
Yohei Yukawab7526452018-10-21 20:15:17 -07002550 resetCurrentMethodAndClient(UnbindReason.SWITCH_IME_FAILED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002551 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002552 } else {
2553 // There is no longer an input method set, so stop any current one.
Yohei Yukawab7526452018-10-21 20:15:17 -07002554 resetCurrentMethodAndClient(UnbindReason.NO_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002555 }
Yohei Yukawa3d46bab2014-05-30 18:10:18 +09002556 // Here is not the perfect place to reset the switching controller. Ideally
2557 // mSwitchingController and mSettings should be able to share the same state.
2558 // TODO: Make sure that mSwitchingController and mSettings are sharing the
2559 // the same enabled IMEs list.
2560 mSwitchingController.resetCircularListLocked(mContext);
Michael Wright7b5a96b2014-08-09 19:28:42 -07002561
2562 }
2563
2564 public void updateKeyboardFromSettingsLocked() {
2565 mShowImeWithHardKeyboard = mSettings.isShowImeWithHardKeyboardEnabled();
2566 if (mSwitchingDialog != null
2567 && mSwitchingDialogTitleView != null
2568 && mSwitchingDialog.isShowing()) {
2569 final Switch hardKeySwitch = (Switch)mSwitchingDialogTitleView.findViewById(
2570 com.android.internal.R.id.hard_keyboard_switch);
2571 hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
2572 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002573 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002574
satokab751aa2010-09-14 19:17:36 +09002575 /* package */ void setInputMethodLocked(String id, int subtypeId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002576 InputMethodInfo info = mMethodMap.get(id);
2577 if (info == null) {
satok913a8922010-08-26 21:53:41 +09002578 throw new IllegalArgumentException("Unknown id: " + id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002579 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002580
satokd81e9502012-05-21 12:58:45 +09002581 // See if we need to notify a subtype change within the same IME.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002582 if (id.equals(mCurMethodId)) {
satokd81e9502012-05-21 12:58:45 +09002583 final int subtypeCount = info.getSubtypeCount();
2584 if (subtypeCount <= 0) {
2585 return;
satokcd7cd292010-11-20 15:46:23 +09002586 }
satokd81e9502012-05-21 12:58:45 +09002587 final InputMethodSubtype oldSubtype = mCurrentSubtype;
2588 final InputMethodSubtype newSubtype;
2589 if (subtypeId >= 0 && subtypeId < subtypeCount) {
2590 newSubtype = info.getSubtypeAt(subtypeId);
2591 } else {
2592 // If subtype is null, try to find the most applicable one from
2593 // getCurrentInputMethodSubtype.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002594 newSubtype = getCurrentInputMethodSubtypeLocked();
satokd81e9502012-05-21 12:58:45 +09002595 }
2596 if (newSubtype == null || oldSubtype == null) {
2597 Slog.w(TAG, "Illegal subtype state: old subtype = " + oldSubtype
2598 + ", new subtype = " + newSubtype);
2599 return;
2600 }
2601 if (newSubtype != oldSubtype) {
2602 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
2603 if (mCurMethod != null) {
2604 try {
Yohei Yukawa849443c2019-01-21 09:02:25 -08002605 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
satokd81e9502012-05-21 12:58:45 +09002606 mCurMethod.changeInputMethodSubtype(newSubtype);
2607 } catch (RemoteException e) {
2608 Slog.w(TAG, "Failed to call changeInputMethodSubtype");
satokab751aa2010-09-14 19:17:36 +09002609 }
2610 }
2611 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002612 return;
2613 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002614
satokd81e9502012-05-21 12:58:45 +09002615 // Changing to a different IME.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002616 final long ident = Binder.clearCallingIdentity();
2617 try {
satokab751aa2010-09-14 19:17:36 +09002618 // Set a subtype to this input method.
2619 // subtypeId the name of a subtype which will be set.
satok723a27e2010-11-11 14:58:11 +09002620 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, false);
2621 // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
2622 // because mCurMethodId is stored as a history in
2623 // setSelectedInputMethodAndSubtypeLocked().
2624 mCurMethodId = id;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002625
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07002626 if (LocalServices.getService(ActivityManagerInternal.class).isSystemReady()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002627 Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08002628 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002629 intent.putExtra("input_method_id", id);
Amith Yamasanicd757062012-10-19 18:23:52 -07002630 mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002631 }
Yohei Yukawab7526452018-10-21 20:15:17 -07002632 unbindCurrentClientLocked(UnbindReason.SWITCH_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002633 } finally {
2634 Binder.restoreCallingIdentity(ident);
2635 }
2636 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002637
satok42c5a162011-05-26 16:46:14 +09002638 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -08002639 public boolean showSoftInput(IInputMethodClient client, int flags,
2640 ResultReceiver resultReceiver) {
Dianne Hackborncef65ee2010-09-30 18:27:22 -07002641 int uid = Binder.getCallingUid();
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002642 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08002643 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002644 return false;
2645 }
2646 final long ident = Binder.clearCallingIdentity();
2647 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002648 if (mCurClient == null || client == null
2649 || mCurClient.client.asBinder() != client.asBinder()) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002650 // We need to check if this is the current client with
2651 // focus in the window manager, to allow this call to
2652 // be made before input is started in it.
Yohei Yukawa41f89c32018-09-19 14:30:04 -07002653 final ClientState cs = mClients.get(client.asBinder());
2654 if (cs == null) {
2655 throw new IllegalArgumentException("unknown client " + client.asBinder());
2656 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002657 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
2658 cs.selfReportedDisplayId)) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002659 Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002660 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002661 }
2662 }
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002663 if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
The Android Open Source Project4df24232009-03-05 14:34:35 -08002664 return showCurrentInputLocked(flags, resultReceiver);
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002665 } finally {
2666 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002667 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002668 }
2669 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002670
Andreas Gamped6d42062018-07-20 13:08:21 -07002671 @GuardedBy("mMethodMap")
The Android Open Source Project4df24232009-03-05 14:34:35 -08002672 boolean showCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002673 mShowRequested = true;
Anna Galusza9b278112016-01-04 11:37:37 -08002674 if (mAccessibilityRequestingNoSoftKeyboard) {
2675 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002676 }
Anna Galusza9b278112016-01-04 11:37:37 -08002677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002678 if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
2679 mShowExplicitlyRequested = true;
2680 mShowForced = true;
Anna Galusza9b278112016-01-04 11:37:37 -08002681 } else if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
2682 mShowExplicitlyRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002683 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002684
Dianne Hackborncc278702009-09-02 23:07:23 -07002685 if (!mSystemReady) {
2686 return false;
2687 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002688
The Android Open Source Project4df24232009-03-05 14:34:35 -08002689 boolean res = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002690 if (mCurMethod != null) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002691 if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + mCurToken);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002692 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
2693 MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod,
2694 resultReceiver));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002695 mInputShown = true;
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002696 if (mHaveConnection && !mVisibleBound) {
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002697 bindCurrentInputMethodServiceLocked(
Yohei Yukawaa67a4592017-03-30 15:57:02 -07002698 mCurIntent, mVisibleConnection, IME_VISIBLE_BIND_FLAGS);
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002699 mVisibleBound = true;
2700 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08002701 res = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002702 } else if (mHaveConnection && SystemClock.uptimeMillis()
satok59b424c2011-09-30 17:21:46 +09002703 >= (mLastBindTime+TIME_TO_RECONNECT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002704 // The client has asked to have the input method shown, but
2705 // we have been sitting here too long with a connection to the
2706 // service and no interface received, so let's disconnect/connect
2707 // to try to prod things along.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002708 EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002709 SystemClock.uptimeMillis()-mLastBindTime,1);
satok59b424c2011-09-30 17:21:46 +09002710 Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002711 mContext.unbindService(this);
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002712 bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002713 } else {
2714 if (DEBUG) {
2715 Slog.d(TAG, "Can't show input: connection = " + mHaveConnection + ", time = "
2716 + ((mLastBindTime+TIME_TO_RECONNECT) - SystemClock.uptimeMillis()));
2717 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002718 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002719
The Android Open Source Project4df24232009-03-05 14:34:35 -08002720 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002721 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002722
satok42c5a162011-05-26 16:46:14 +09002723 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -08002724 public boolean hideSoftInput(IInputMethodClient client, int flags,
2725 ResultReceiver resultReceiver) {
Dianne Hackborncef65ee2010-09-30 18:27:22 -07002726 int uid = Binder.getCallingUid();
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002727 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08002728 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002729 return false;
2730 }
2731 final long ident = Binder.clearCallingIdentity();
2732 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002733 if (mCurClient == null || client == null
2734 || mCurClient.client.asBinder() != client.asBinder()) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002735 // We need to check if this is the current client with
2736 // focus in the window manager, to allow this call to
2737 // be made before input is started in it.
Yohei Yukawa41f89c32018-09-19 14:30:04 -07002738 final ClientState cs = mClients.get(client.asBinder());
2739 if (cs == null) {
2740 throw new IllegalArgumentException("unknown client " + client.asBinder());
2741 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002742 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
2743 cs.selfReportedDisplayId)) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002744 if (DEBUG) {
2745 Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002746 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08002747 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002748 }
2749 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002750
Joe Onorato8a9b2202010-02-26 18:56:32 -08002751 if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
The Android Open Source Project4df24232009-03-05 14:34:35 -08002752 return hideCurrentInputLocked(flags, resultReceiver);
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002753 } finally {
2754 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002755 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002756 }
2757 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002758
The Android Open Source Project4df24232009-03-05 14:34:35 -08002759 boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002760 if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
2761 && (mShowExplicitlyRequested || mShowForced)) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002762 if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
The Android Open Source Project4df24232009-03-05 14:34:35 -08002763 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002764 }
2765 if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002766 if (DEBUG) Slog.v(TAG, "Not hiding: forced show not cancelled by not-always hide");
The Android Open Source Project4df24232009-03-05 14:34:35 -08002767 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002768 }
Seigo Nonakaec928652015-06-10 15:31:20 +09002769
2770 // There is a chance that IMM#hideSoftInput() is called in a transient state where
2771 // IMMS#InputShown is already updated to be true whereas IMMS#mImeWindowVis is still waiting
2772 // to be updated with the new value sent from IME process. Even in such a transient state
2773 // historically we have accepted an incoming call of IMM#hideSoftInput() from the
2774 // application process as a valid request, and have even promised such a behavior with CTS
2775 // since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only
2776 // IMMS#InputShown indicates that the software keyboard is shown.
2777 // TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
2778 final boolean shouldHideSoftInput = (mCurMethod != null) && (mInputShown ||
2779 (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002780 boolean res;
Seigo Nonakaec928652015-06-10 15:31:20 +09002781 if (shouldHideSoftInput) {
2782 // The IME will report its visible state again after the following message finally
2783 // delivered to the IME process as an IPC. Hence the inconsistency between
2784 // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
2785 // the final state.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002786 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
2787 MSG_HIDE_SOFT_INPUT, mCurMethod, resultReceiver));
2788 res = true;
2789 } else {
2790 res = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002791 }
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002792 if (mHaveConnection && mVisibleBound) {
2793 mContext.unbindService(mVisibleConnection);
2794 mVisibleBound = false;
2795 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002796 mInputShown = false;
2797 mShowRequested = false;
2798 mShowExplicitlyRequested = false;
2799 mShowForced = false;
The Android Open Source Project4df24232009-03-05 14:34:35 -08002800 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002801 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002802
Yohei Yukawa2553e482017-12-15 15:47:33 -08002803 @NonNull
satok42c5a162011-05-26 16:46:14 +09002804 @Override
Yohei Yukawa05c25f82016-02-22 12:41:17 -08002805 public InputBindResult startInputOrWindowGainedFocus(
Yohei Yukawadc66e522018-10-21 10:43:14 -07002806 @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002807 @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
2808 int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
Yohei Yukawadc66e522018-10-21 10:43:14 -07002809 @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) {
Yohei Yukawa80498d52018-06-21 16:24:36 -07002810 if (windowToken == null) {
2811 Slog.e(TAG, "windowToken cannot be null.");
2812 return InputBindResult.NULL;
Yohei Yukawa05c25f82016-02-22 12:41:17 -08002813 }
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002814 final int callingUserId = UserHandle.getCallingUserId();
2815 final int userId;
Yohei Yukawa716897c2019-01-22 00:00:53 -08002816 if (attribute != null && attribute.targetInputMethodUser != null
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002817 && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
2818 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Yohei Yukawa670abea2019-01-28 00:00:50 -08002819 "Using EditorInfo.targetInputMethodUser requires INTERACT_ACROSS_USERS_FULL.");
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002820 userId = attribute.targetInputMethodUser.getIdentifier();
2821 if (!mUserManagerInternal.isUserRunning(userId)) {
2822 // There is a chance that we hit here because of race condition. Let's just return
2823 // an error code instead of crashing the caller process, which at least has
2824 // INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important process.
2825 Slog.e(TAG, "User #" + userId + " is not running.");
2826 return InputBindResult.INVALID_USER;
2827 }
2828 } else {
2829 userId = callingUserId;
2830 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002831 final InputBindResult result;
2832 synchronized (mMethodMap) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002833 final long ident = Binder.clearCallingIdentity();
2834 try {
2835 result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client,
2836 windowToken, startInputFlags, softInputMode, windowFlags, attribute,
2837 inputContext, missingMethods, unverifiedTargetSdkVersion, userId);
2838 } finally {
2839 Binder.restoreCallingIdentity(ident);
2840 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002841 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002842 if (result == null) {
2843 // This must never happen, but just in case.
2844 Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
Yohei Yukawaa468d702018-10-21 11:42:34 -07002845 + InputMethodDebug.startInputReasonToString(startInputReason)
Yohei Yukawa2553e482017-12-15 15:47:33 -08002846 + " windowFlags=#" + Integer.toHexString(windowFlags)
2847 + " editorInfo=" + attribute);
2848 return InputBindResult.NULL;
2849 }
2850 return result;
Yohei Yukawa05c25f82016-02-22 12:41:17 -08002851 }
2852
Yohei Yukawa2553e482017-12-15 15:47:33 -08002853 @NonNull
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002854 private InputBindResult startInputOrWindowGainedFocusInternalLocked(
Yohei Yukawadc66e522018-10-21 10:43:14 -07002855 @StartInputReason int startInputReason, IInputMethodClient client,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002856 @NonNull IBinder windowToken, @StartInputFlags int startInputFlags,
2857 @SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute,
2858 IInputContext inputContext, @MissingMethodFlags int missingMethods,
Yohei Yukawa4391c202019-01-28 00:49:10 -08002859 int unverifiedTargetSdkVersion, @UserIdInt int userId) {
Yohei Yukawa67464522019-01-28 00:50:09 -08002860 if (DEBUG) {
2861 Slog.v(TAG, "startInputOrWindowGainedFocusInternalLocked: reason="
2862 + InputMethodDebug.startInputReasonToString(startInputReason)
2863 + " client=" + client.asBinder()
2864 + " inputContext=" + inputContext
2865 + " missingMethods="
2866 + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
2867 + " attribute=" + attribute
2868 + " startInputFlags="
2869 + InputMethodDebug.startInputFlagsToString(startInputFlags)
2870 + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode)
2871 + " windowFlags=#" + Integer.toHexString(windowFlags)
2872 + " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion);
2873 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002874
Yohei Yukawa67464522019-01-28 00:50:09 -08002875 final int windowDisplayId = mWindowManagerInternal.getDisplayIdForWindow(windowToken);
2876
2877 final ClientState cs = mClients.get(client.asBinder());
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002878 if (cs == null) {
Yohei Yukawa67464522019-01-28 00:50:09 -08002879 throw new IllegalArgumentException("unknown client " + client.asBinder());
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002880 }
2881 if (cs.selfReportedDisplayId != windowDisplayId) {
2882 Slog.e(TAG, "startInputOrWindowGainedFocusInternal: display ID mismatch."
2883 + " from client:" + cs.selfReportedDisplayId
2884 + " from window:" + windowDisplayId);
2885 return InputBindResult.DISPLAY_ID_MISMATCH;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002886 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08002887
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002888 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
2889 cs.selfReportedDisplayId)) {
2890 // Check with the window manager to make sure this client actually
2891 // has a window with focus. If not, reject. This is thread safe
2892 // because if the focus changes some time before or after, the
2893 // next client receiving focus that has any interest in input will
2894 // be calling through here after that change happens.
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002895 if (DEBUG) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002896 Slog.w(TAG, "Focus gain on non-focused client " + cs.client
2897 + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002898 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002899 return InputBindResult.NOT_IME_TARGET_WINDOW;
2900 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002901
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002902 // cross-profile access is always allowed here to allow profile-switching.
2903 if (!mSettings.isCurrentProfile(userId)) {
2904 Slog.w(TAG, "A background user is requesting window. Hiding IME.");
2905 Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
2906 + " a background user, use EditorInfo.targetInputMethodUser with"
2907 + " INTERACT_ACROSS_USERS_FULL permission.");
2908 hideCurrentInputLocked(0, null);
2909 return InputBindResult.INVALID_USER;
2910 }
2911
2912 if (PER_PROFILE_IME_ENABLED && userId != mSettings.getCurrentUserId()) {
2913 switchUserLocked(userId);
2914 }
2915 // Master feature flag that overrides other conditions and forces IME preRendering.
2916 if (DEBUG) {
2917 Slog.v(TAG, "IME PreRendering MASTER flag: "
Yohei Yukawa67464522019-01-28 00:50:09 -08002918 + DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() + ", LowRam: " + mIsLowRam);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002919 }
2920 // pre-rendering not supported on low-ram devices.
2921 cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam;
2922
2923 if (mCurFocusedWindow == windowToken) {
2924 if (DEBUG) {
2925 Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
2926 + " attribute=" + attribute + ", token = " + windowToken);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002927 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002928 if (attribute != null) {
2929 return startInputUncheckedLocked(cs, inputContext, missingMethods,
2930 attribute, startInputFlags, startInputReason);
2931 }
2932 return new InputBindResult(
2933 InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
2934 null, null, null, -1);
2935 }
2936 mCurFocusedWindow = windowToken;
2937 mCurFocusedWindowSoftInputMode = softInputMode;
2938 mCurFocusedWindowClient = cs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002939
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002940 // Should we auto-show the IME even if the caller has not
2941 // specified what should be done with it?
2942 // We only do this automatically if the window can resize
2943 // to accommodate the IME (so what the user sees will give
2944 // them good context without input information being obscured
2945 // by the IME) or if running on a large screen where there
2946 // is more room for the target window + IME.
2947 final boolean doAutoShow =
Yohei Yukawa6e875592019-01-28 00:49:30 -08002948 (softInputMode & LayoutParams.SOFT_INPUT_MASK_ADJUST)
2949 == LayoutParams.SOFT_INPUT_ADJUST_RESIZE
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002950 || mRes.getConfiguration().isLayoutSizeAtLeast(
2951 Configuration.SCREENLAYOUT_SIZE_LARGE);
Yohei Yukawa67464522019-01-28 00:50:09 -08002952 final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002953
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002954 // We want to start input before showing the IME, but after closing
2955 // it. We want to do this after closing it to help the IME disappear
2956 // more quickly (not get stuck behind it initializing itself for the
2957 // new focused input, even if its window wants to hide the IME).
2958 boolean didStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002959
Yohei Yukawa67464522019-01-28 00:50:09 -08002960 InputBindResult res = null;
Yohei Yukawa6e875592019-01-28 00:49:30 -08002961 switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) {
2962 case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002963 if (!isTextEditor || !doAutoShow) {
Yohei Yukawa6e875592019-01-28 00:49:30 -08002964 if (LayoutParams.mayUseInputMethod(windowFlags)) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002965 // There is no focus view, and this window will
2966 // be behind any soft input window, so hide the
2967 // soft input window if it is shown.
2968 if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
2969 hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002970
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002971 // If focused display changed, we should unbind current method
2972 // to make app window in previous display relayout after Ime
2973 // window token removed.
2974 // Note that we can trust client's display ID as long as it matches
2975 // to the display ID obtained from the window.
2976 if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
2977 unbindCurrentMethodLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002978 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002979 }
Yohei Yukawa6e875592019-01-28 00:49:30 -08002980 } else if (isTextEditor && doAutoShow
2981 && (softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002982 // There is a focus view, and we are navigating forward
2983 // into the window, so show the input window for the user.
2984 // We only do this automatically if the window can resize
2985 // to accommodate the IME (so what the user sees will give
2986 // them good context without input information being obscured
2987 // by the IME) or if running on a large screen where there
2988 // is more room for the target window + IME.
2989 if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
2990 if (attribute != null) {
2991 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
2992 attribute, startInputFlags, startInputReason);
2993 didStart = true;
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002994 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002995 showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
2996 }
2997 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08002998 case LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002999 // Do nothing.
3000 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003001 case LayoutParams.SOFT_INPUT_STATE_HIDDEN:
3002 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003003 if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003004 hideCurrentInputLocked(0, null);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003005 }
3006 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003007 case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003008 if (DEBUG) Slog.v(TAG, "Window asks to hide input");
3009 hideCurrentInputLocked(0, null);
3010 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003011 case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
3012 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003013 if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003014 if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
3015 unverifiedTargetSdkVersion, startInputFlags)) {
3016 if (attribute != null) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003017 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3018 attribute, startInputFlags, startInputReason);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003019 didStart = true;
3020 }
3021 showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
3022 } else {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003023 Slog.e(TAG, "SOFT_INPUT_STATE_VISIBLE is ignored because"
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003024 + " there is no focused view that also returns true from"
3025 + " View#onCheckIsTextEditor()");
3026 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003027 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003028 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003029 case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003030 if (DEBUG) Slog.v(TAG, "Window asks to always show input");
3031 if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
3032 unverifiedTargetSdkVersion, startInputFlags)) {
3033 if (attribute != null) {
3034 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3035 attribute, startInputFlags, startInputReason);
3036 didStart = true;
3037 }
3038 showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
3039 } else {
3040 Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
3041 + " there is no focused view that also returns true from"
3042 + " View#onCheckIsTextEditor()");
3043 }
3044 break;
3045 }
3046
3047 if (!didStart) {
3048 if (attribute != null) {
3049 if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
3050 || (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003051 res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003052 startInputFlags, startInputReason);
3053 } else {
3054 res = InputBindResult.NO_EDITOR;
3055 }
3056 } else {
3057 res = InputBindResult.NULL_EDITOR_INFO;
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003058 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003059 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08003060 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003061 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003062
Guliz Tuncay6908c152017-06-02 16:06:10 -07003063 private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003064 // TODO(yukawa): multi-display support.
Guliz Tuncay6908c152017-06-02 16:06:10 -07003065 final int uid = Binder.getCallingUid();
lumark0b05f9e2018-11-26 15:09:06 +08003066 if (mCurFocusedWindowClient != null && client != null
Tarandeep Singheb570612018-01-29 16:20:32 -08003067 && mCurFocusedWindowClient.client.asBinder() == client.asBinder()) {
Guliz Tuncay6908c152017-06-02 16:06:10 -07003068 return true;
3069 } else if (mCurIntent != null && InputMethodUtils.checkIfPackageBelongsToUid(
3070 mAppOpsManager,
3071 uid,
3072 mCurIntent.getComponent().getPackageName())) {
3073 return true;
Guliz Tuncay6908c152017-06-02 16:06:10 -07003074 }
Guliz Tuncay6908c152017-06-02 16:06:10 -07003075 return false;
3076 }
3077
satok42c5a162011-05-26 16:46:14 +09003078 @Override
Seigo Nonaka14e13912015-05-06 21:04:13 -07003079 public void showInputMethodPickerFromClient(
3080 IInputMethodClient client, int auxiliarySubtypeMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003081 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003082 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003083 return;
3084 }
Guliz Tuncay6908c152017-06-02 16:06:10 -07003085 if(!canShowInputMethodPickerLocked(client)) {
satok47a44912010-10-06 16:03:58 +09003086 Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
Dianne Hackborncef65ee2010-09-30 18:27:22 -07003087 + Binder.getCallingUid() + ": " + client);
Guliz Tuncay6908c152017-06-02 16:06:10 -07003088 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003089 }
3090
satok440aab52010-11-25 09:43:11 +09003091 // Always call subtype picker, because subtype picker is a superset of input method
3092 // picker.
lumark0b05f9e2018-11-26 15:09:06 +08003093 mHandler.sendMessage(mCaller.obtainMessageII(
3094 MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode,
3095 (mCurClient != null) ? mCurClient.selfReportedDisplayId : DEFAULT_DISPLAY));
satokab751aa2010-09-14 19:17:36 +09003096 }
3097 }
3098
lumark0b05f9e2018-11-26 15:09:06 +08003099 @Override
3100 public void showInputMethodPickerFromSystem(IInputMethodClient client, int auxiliarySubtypeMode,
3101 int displayId) {
3102 if (mContext.checkCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
3103 != PackageManager.PERMISSION_GRANTED) {
3104 throw new SecurityException(
3105 "showInputMethodPickerFromSystem requires WRITE_SECURE_SETTINGS permission");
3106 }
3107 // Always call subtype picker, because subtype picker is a superset of input method
3108 // picker.
3109 mHandler.sendMessage(mCaller.obtainMessageII(
3110 MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode, displayId));
3111 }
3112
Tarandeep Singheb570612018-01-29 16:20:32 -08003113 public boolean isInputMethodPickerShownForTest() {
3114 synchronized(mMethodMap) {
3115 if (mSwitchingDialog == null) {
3116 return false;
3117 }
3118 return mSwitchingDialog.isShowing();
3119 }
3120 }
3121
Yohei Yukawa0c1ebff2018-12-27 14:06:28 -08003122 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003123 private void setInputMethod(@NonNull IBinder token, String id) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003124 synchronized (mMethodMap) {
Yohei Yukawa0c1ebff2018-12-27 14:06:28 -08003125 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003126 return;
3127 }
3128 setInputMethodWithSubtypeIdLocked(token, id, NOT_A_SUBTYPE_ID);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003129 }
satok28203512010-11-24 11:06:49 +09003130 }
3131
Yohei Yukawa4773ee12018-12-24 21:13:53 -08003132 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003133 private void setInputMethodAndSubtype(@NonNull IBinder token, String id,
3134 InputMethodSubtype subtype) {
satok28203512010-11-24 11:06:49 +09003135 synchronized (mMethodMap) {
Yohei Yukawa4773ee12018-12-24 21:13:53 -08003136 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003137 return;
3138 }
satok28203512010-11-24 11:06:49 +09003139 if (subtype != null) {
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003140 setInputMethodWithSubtypeIdLocked(token, id,
3141 InputMethodUtils.getSubtypeIdFromHashCode(mMethodMap.get(id),
3142 subtype.hashCode()));
satok28203512010-11-24 11:06:49 +09003143 } else {
3144 setInputMethod(token, id);
3145 }
3146 }
satokab751aa2010-09-14 19:17:36 +09003147 }
3148
satok42c5a162011-05-26 16:46:14 +09003149 @Override
satokb416a712010-11-25 20:42:14 +09003150 public void showInputMethodAndSubtypeEnablerFromClient(
satok217f5482010-12-15 05:19:19 +09003151 IInputMethodClient client, String inputMethodId) {
satokb416a712010-11-25 20:42:14 +09003152 synchronized (mMethodMap) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003153 // TODO(yukawa): Should we verify the display ID?
Yohei Yukawa46d74762019-01-22 10:17:22 -08003154 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003155 return;
3156 }
satok7fee71f2010-12-17 18:54:26 +09003157 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
3158 MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
satokb416a712010-11-25 20:42:14 +09003159 }
3160 }
3161
Yohei Yukawa0c499082018-12-09 18:52:02 -08003162 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003163 private boolean switchToPreviousInputMethod(@NonNull IBinder token) {
satok735cf382010-11-11 20:40:09 +09003164 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003165 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa0c499082018-12-09 18:52:02 -08003166 return false;
3167 }
satokc445bcd2011-01-25 18:57:24 +09003168 final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
satok4fc87d62011-05-20 16:13:43 +09003169 final InputMethodInfo lastImi;
satok208d5632011-05-20 22:13:38 +09003170 if (lastIme != null) {
satok4fc87d62011-05-20 16:13:43 +09003171 lastImi = mMethodMap.get(lastIme.first);
3172 } else {
3173 lastImi = null;
satok735cf382010-11-11 20:40:09 +09003174 }
satok4fc87d62011-05-20 16:13:43 +09003175 String targetLastImiId = null;
3176 int subtypeId = NOT_A_SUBTYPE_ID;
3177 if (lastIme != null && lastImi != null) {
3178 final boolean imiIdIsSame = lastImi.getId().equals(mCurMethodId);
Narayan Kamatha09b4d22016-04-15 18:32:45 +01003179 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
satok4fc87d62011-05-20 16:13:43 +09003180 final int currentSubtypeHash = mCurrentSubtype == null ? NOT_A_SUBTYPE_ID
3181 : mCurrentSubtype.hashCode();
3182 // If the last IME is the same as the current IME and the last subtype is not
3183 // defined, there is no need to switch to the last IME.
3184 if (!imiIdIsSame || lastSubtypeHash != currentSubtypeHash) {
3185 targetLastImiId = lastIme.first;
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003186 subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
satok4fc87d62011-05-20 16:13:43 +09003187 }
3188 }
3189
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003190 if (TextUtils.isEmpty(targetLastImiId)
3191 && !InputMethodUtils.canAddToLastInputMethod(mCurrentSubtype)) {
satok4fc87d62011-05-20 16:13:43 +09003192 // This is a safety net. If the currentSubtype can't be added to the history
3193 // and the framework couldn't find the last ime, we will make the last ime be
3194 // the most applicable enabled keyboard subtype of the system imes.
3195 final List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
3196 if (enabled != null) {
3197 final int N = enabled.size();
3198 final String locale = mCurrentSubtype == null
3199 ? mRes.getConfiguration().locale.toString()
3200 : mCurrentSubtype.getLocale();
3201 for (int i = 0; i < N; ++i) {
3202 final InputMethodInfo imi = enabled.get(i);
Yohei Yukawafd70fe82018-04-08 12:19:56 -07003203 if (imi.getSubtypeCount() > 0 && imi.isSystem()) {
satok4fc87d62011-05-20 16:13:43 +09003204 InputMethodSubtype keyboardSubtype =
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003205 InputMethodUtils.findLastResortApplicableSubtypeLocked(mRes,
3206 InputMethodUtils.getSubtypes(imi),
3207 InputMethodUtils.SUBTYPE_MODE_KEYBOARD, locale, true);
satok4fc87d62011-05-20 16:13:43 +09003208 if (keyboardSubtype != null) {
3209 targetLastImiId = imi.getId();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003210 subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
satok4fc87d62011-05-20 16:13:43 +09003211 imi, keyboardSubtype.hashCode());
3212 if(keyboardSubtype.getLocale().equals(locale)) {
3213 break;
3214 }
3215 }
3216 }
3217 }
3218 }
3219 }
3220
3221 if (!TextUtils.isEmpty(targetLastImiId)) {
3222 if (DEBUG) {
3223 Slog.d(TAG, "Switch to: " + lastImi.getId() + ", " + lastIme.second
3224 + ", from: " + mCurMethodId + ", " + subtypeId);
3225 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003226 setInputMethodWithSubtypeIdLocked(token, targetLastImiId, subtypeId);
satok4fc87d62011-05-20 16:13:43 +09003227 return true;
3228 } else {
3229 return false;
3230 }
satok735cf382010-11-11 20:40:09 +09003231 }
3232 }
3233
Yohei Yukawa70f17e72018-12-09 18:51:38 -08003234 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003235 private boolean switchToNextInputMethod(@NonNull IBinder token, boolean onlyCurrentIme) {
satok688bd472012-02-09 20:09:17 +09003236 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003237 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawaa0755742014-06-04 20:28:18 +09003238 return false;
3239 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003240 final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
Yohei Yukawa136b6ce2018-05-02 10:55:35 -07003241 onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype);
satok688bd472012-02-09 20:09:17 +09003242 if (nextSubtype == null) {
3243 return false;
3244 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003245 setInputMethodWithSubtypeIdLocked(token, nextSubtype.mImi.getId(),
3246 nextSubtype.mSubtypeId);
satok688bd472012-02-09 20:09:17 +09003247 return true;
3248 }
3249 }
3250
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003251 @BinderThread
3252 private boolean shouldOfferSwitchingToNextInputMethod(@NonNull IBinder token) {
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09003253 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003254 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawaa0755742014-06-04 20:28:18 +09003255 return false;
3256 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003257 final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
Yohei Yukawa136b6ce2018-05-02 10:55:35 -07003258 false /* onlyCurrentIme */, mMethodMap.get(mCurMethodId), mCurrentSubtype);
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09003259 if (nextSubtype == null) {
3260 return false;
3261 }
3262 return true;
3263 }
3264 }
3265
3266 @Override
satok68f1b782011-04-11 14:26:04 +09003267 public InputMethodSubtype getLastInputMethodSubtype() {
3268 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003269 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003270 return null;
3271 }
satok68f1b782011-04-11 14:26:04 +09003272 final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
3273 // TODO: Handle the case of the last IME with no subtypes
3274 if (lastIme == null || TextUtils.isEmpty(lastIme.first)
3275 || TextUtils.isEmpty(lastIme.second)) return null;
3276 final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
3277 if (lastImi == null) return null;
3278 try {
Narayan Kamatha09b4d22016-04-15 18:32:45 +01003279 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003280 final int lastSubtypeId =
3281 InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
satok0e7d7d62011-07-05 13:28:06 +09003282 if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
3283 return null;
3284 }
3285 return lastImi.getSubtypeAt(lastSubtypeId);
satok68f1b782011-04-11 14:26:04 +09003286 } catch (NumberFormatException e) {
3287 return null;
3288 }
3289 }
3290 }
3291
satoke7c6998e2011-06-03 17:57:59 +09003292 @Override
satokee5e77c2011-09-02 18:50:15 +09003293 public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
satok91e88122011-07-18 11:11:42 +09003294 // By this IPC call, only a process which shares the same uid with the IME can add
3295 // additional input method subtypes to the IME.
Yohei Yukawa70f5c482016-01-04 19:42:36 -08003296 if (TextUtils.isEmpty(imiId) || subtypes == null) return;
Yohei Yukawab557d572018-12-29 21:26:26 -08003297 final ArrayList<InputMethodSubtype> toBeAdded = new ArrayList<>();
3298 for (InputMethodSubtype subtype : subtypes) {
3299 if (!toBeAdded.contains(subtype)) {
3300 toBeAdded.add(subtype);
3301 } else {
3302 Slog.w(TAG, "Duplicated subtype definition found: "
3303 + subtype.getLocale() + ", " + subtype.getMode());
3304 }
3305 }
satoke7c6998e2011-06-03 17:57:59 +09003306 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003307 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003308 return;
3309 }
Yohei Yukawa79247822017-01-23 15:26:15 -08003310 if (!mSystemReady) {
3311 return;
3312 }
satok91e88122011-07-18 11:11:42 +09003313 final InputMethodInfo imi = mMethodMap.get(imiId);
satokee5e77c2011-09-02 18:50:15 +09003314 if (imi == null) return;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003315 final String[] packageInfos;
3316 try {
3317 packageInfos = mIPackageManager.getPackagesForUid(Binder.getCallingUid());
3318 } catch (RemoteException e) {
3319 Slog.e(TAG, "Failed to get package infos");
3320 return;
3321 }
satok91e88122011-07-18 11:11:42 +09003322 if (packageInfos != null) {
3323 final int packageNum = packageInfos.length;
3324 for (int i = 0; i < packageNum; ++i) {
3325 if (packageInfos[i].equals(imi.getPackageName())) {
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003326 if (subtypes.length > 0) {
Yohei Yukawab557d572018-12-29 21:26:26 -08003327 mAdditionalSubtypeMap.put(imi.getId(), toBeAdded);
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003328 } else {
Yohei Yukawab557d572018-12-29 21:26:26 -08003329 mAdditionalSubtypeMap.remove(imi.getId());
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003330 }
Yohei Yukawab557d572018-12-29 21:26:26 -08003331 AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
3332 mSettings.getCurrentUserId());
satokc5933802011-08-31 21:26:04 +09003333 final long ident = Binder.clearCallingIdentity();
3334 try {
Yohei Yukawa94e33302016-02-12 19:37:03 -08003335 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
satokc5933802011-08-31 21:26:04 +09003336 } finally {
3337 Binder.restoreCallingIdentity(ident);
3338 }
satokee5e77c2011-09-02 18:50:15 +09003339 return;
satok91e88122011-07-18 11:11:42 +09003340 }
3341 }
3342 }
satoke7c6998e2011-06-03 17:57:59 +09003343 }
satokee5e77c2011-09-02 18:50:15 +09003344 return;
satoke7c6998e2011-06-03 17:57:59 +09003345 }
3346
Yohei Yukawab985e6e2018-09-05 17:07:52 -07003347 /**
3348 * This is kept due to {@link android.annotation.UnsupportedAppUsage} in
3349 * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in
3350 * {@link InputMethodService#onCreate()}.
3351 *
3352 * <p>TODO(Bug 113914148): Check if we can remove this.</p>
3353 * @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight()}
3354 */
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09003355 @Override
3356 public int getInputMethodWindowVisibleHeight() {
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003357 // TODO(yukawa): Should we verify the display ID?
lumark90120a82018-08-15 00:33:03 +08003358 return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09003359 }
3360
Yohei Yukawac54c1172018-09-06 11:39:50 -07003361 @BinderThread
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003362 private void notifyUserAction(@NonNull IBinder token) {
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003363 if (DEBUG) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003364 Slog.d(TAG, "Got the notification of a user action.");
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003365 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003366 synchronized (mMethodMap) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003367 if (mCurToken != token) {
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09003368 if (DEBUG) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003369 Slog.d(TAG, "Ignoring the user action notification from IMEs that are no longer"
3370 + " active.");
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09003371 }
3372 return;
3373 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003374 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
3375 if (imi != null) {
Yohei Yukawa02970512014-06-05 16:16:18 +09003376 mSwitchingController.onUserActionLocked(imi, mCurrentSubtype);
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003377 }
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003378 }
3379 }
3380
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003381 @BinderThread
3382 private void reportPreRendered(IBinder token, EditorInfo info) {
3383 synchronized (mMethodMap) {
3384 if (!calledWithValidTokenLocked(token)) {
3385 return;
3386 }
3387 if (mCurClient != null && mCurClient.client != null) {
3388 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
3389 MSG_REPORT_PRE_RENDERED, info, mCurClient));
3390 }
3391 }
3392 }
3393
3394 @BinderThread
3395 private void applyImeVisibility(IBinder token, boolean setVisible) {
3396 synchronized (mMethodMap) {
3397 if (!calledWithValidTokenLocked(token)) {
3398 return;
3399 }
3400 if (mCurClient != null && mCurClient.client != null) {
3401 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
3402 MSG_APPLY_IME_VISIBILITY, setVisible ? 1 : 0, mCurClient));
3403 }
3404 }
3405 }
3406
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003407 private void setInputMethodWithSubtypeIdLocked(IBinder token, String id, int subtypeId) {
3408 if (token == null) {
3409 if (mContext.checkCallingOrSelfPermission(
3410 android.Manifest.permission.WRITE_SECURE_SETTINGS)
3411 != PackageManager.PERMISSION_GRANTED) {
3412 throw new SecurityException(
3413 "Using null token requires permission "
3414 + android.Manifest.permission.WRITE_SECURE_SETTINGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003415 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003416 } else if (mCurToken != token) {
3417 Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
3418 + " token: " + token);
3419 return;
3420 }
3421
3422 final long ident = Binder.clearCallingIdentity();
3423 try {
3424 setInputMethodLocked(id, subtypeId);
3425 } finally {
3426 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003427 }
3428 }
3429
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003430 @BinderThread
3431 private void hideMySoftInput(@NonNull IBinder token, int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003432 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003433 if (!calledWithValidTokenLocked(token)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003434 return;
3435 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003436 long ident = Binder.clearCallingIdentity();
3437 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003438 hideCurrentInputLocked(flags, null);
3439 } finally {
3440 Binder.restoreCallingIdentity(ident);
3441 }
3442 }
3443 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003444
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003445 @BinderThread
3446 private void showMySoftInput(@NonNull IBinder token, int flags) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003447 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003448 if (!calledWithValidTokenLocked(token)) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003449 return;
3450 }
3451 long ident = Binder.clearCallingIdentity();
3452 try {
3453 showCurrentInputLocked(flags, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003454 } finally {
3455 Binder.restoreCallingIdentity(ident);
3456 }
3457 }
3458 }
3459
3460 void setEnabledSessionInMainThread(SessionState session) {
3461 if (mEnabledSession != session) {
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003462 if (mEnabledSession != null && mEnabledSession.session != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003463 try {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003464 if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003465 mEnabledSession.method.setSessionEnabled(mEnabledSession.session, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003466 } catch (RemoteException e) {
3467 }
3468 }
3469 mEnabledSession = session;
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003470 if (mEnabledSession != null && mEnabledSession.session != null) {
3471 try {
3472 if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
3473 mEnabledSession.method.setSessionEnabled(mEnabledSession.session, true);
3474 } catch (RemoteException e) {
3475 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 }
3477 }
3478 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003479
Yohei Yukawa930328c2017-10-18 20:19:53 -07003480 @MainThread
satok42c5a162011-05-26 16:46:14 +09003481 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003482 public boolean handleMessage(Message msg) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003483 SomeArgs args;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003484 switch (msg.what) {
satokab751aa2010-09-14 19:17:36 +09003485 case MSG_SHOW_IM_SUBTYPE_PICKER:
Seigo Nonaka14e13912015-05-06 21:04:13 -07003486 final boolean showAuxSubtypes;
lumark0b05f9e2018-11-26 15:09:06 +08003487 final int displayId = msg.arg2;
Seigo Nonaka14e13912015-05-06 21:04:13 -07003488 switch (msg.arg1) {
3489 case InputMethodManager.SHOW_IM_PICKER_MODE_AUTO:
3490 // This is undocumented so far, but IMM#showInputMethodPicker() has been
3491 // implemented so that auxiliary subtypes will be excluded when the soft
3492 // keyboard is invisible.
3493 showAuxSubtypes = mInputShown;
3494 break;
3495 case InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES:
3496 showAuxSubtypes = true;
3497 break;
3498 case InputMethodManager.SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES:
3499 showAuxSubtypes = false;
3500 break;
3501 default:
3502 Slog.e(TAG, "Unknown subtype picker mode = " + msg.arg1);
3503 return false;
3504 }
lumark0b05f9e2018-11-26 15:09:06 +08003505 showInputMethodMenu(showAuxSubtypes, displayId);
satokab751aa2010-09-14 19:17:36 +09003506 return true;
3507
satok47a44912010-10-06 16:03:58 +09003508 case MSG_SHOW_IM_SUBTYPE_ENABLER:
Yohei Yukawa41f34272015-12-14 15:41:52 -08003509 showInputMethodAndSubtypeEnabler((String)msg.obj);
satok217f5482010-12-15 05:19:19 +09003510 return true;
3511
3512 case MSG_SHOW_IM_CONFIG:
3513 showConfigureInputMethods();
satok47a44912010-10-06 16:03:58 +09003514 return true;
3515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003518 case MSG_UNBIND_INPUT:
3519 try {
3520 ((IInputMethod)msg.obj).unbindInput();
3521 } catch (RemoteException e) {
3522 // There is nothing interesting about the method dying.
3523 }
3524 return true;
3525 case MSG_BIND_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003526 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003527 try {
3528 ((IInputMethod)args.arg1).bindInput((InputBinding)args.arg2);
3529 } catch (RemoteException e) {
3530 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003531 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003532 return true;
3533 case MSG_SHOW_SOFT_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003534 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003535 try {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003536 if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput("
Craig Mautner6efb4c72013-03-13 10:17:41 -07003537 + msg.arg1 + ", " + args.arg2 + ")");
Craig Mautnerca0ac712013-03-14 09:43:02 -07003538 ((IInputMethod)args.arg1).showSoftInput(msg.arg1, (ResultReceiver)args.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003539 } catch (RemoteException e) {
3540 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003541 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003542 return true;
3543 case MSG_HIDE_SOFT_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003544 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003545 try {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003546 if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, "
Craig Mautner6efb4c72013-03-13 10:17:41 -07003547 + args.arg2 + ")");
Craig Mautnerca0ac712013-03-14 09:43:02 -07003548 ((IInputMethod)args.arg1).hideSoftInput(0, (ResultReceiver)args.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003549 } catch (RemoteException e) {
3550 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003551 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003552 return true;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07003553 case MSG_HIDE_CURRENT_INPUT_METHOD:
3554 synchronized (mMethodMap) {
3555 hideCurrentInputLocked(0, null);
3556 }
3557 return true;
Yohei Yukawac54c1172018-09-06 11:39:50 -07003558 case MSG_INITIALIZE_IME:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003559 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003560 try {
lumark90120a82018-08-15 00:33:03 +08003561 if (DEBUG) {
3562 Slog.v(TAG, "Sending attach of token: " + args.arg2 + " for display: "
3563 + msg.arg1);
3564 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07003565 final IBinder token = (IBinder) args.arg2;
lumark90120a82018-08-15 00:33:03 +08003566 ((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
Yohei Yukawac54c1172018-09-06 11:39:50 -07003567 new InputMethodPrivilegedOperationsImpl(this, token));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003568 } catch (RemoteException e) {
3569 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003570 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003571 return true;
Jeff Brownc28867a2013-03-26 15:42:39 -07003572 case MSG_CREATE_SESSION: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003573 args = (SomeArgs)msg.obj;
Jeff Brown1951ce82013-04-04 22:45:12 -07003574 IInputMethod method = (IInputMethod)args.arg1;
Jeff Brownc28867a2013-03-26 15:42:39 -07003575 InputChannel channel = (InputChannel)args.arg2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003576 try {
Jeff Brown1951ce82013-04-04 22:45:12 -07003577 method.createSession(channel, (IInputSessionCallback)args.arg3);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003578 } catch (RemoteException e) {
Jeff Brownc28867a2013-03-26 15:42:39 -07003579 } finally {
Jeff Brown1951ce82013-04-04 22:45:12 -07003580 // Dispose the channel if the input method is not local to this process
3581 // because the remote proxy will get its own copy when unparceled.
3582 if (channel != null && Binder.isProxy(method)) {
Jeff Brownc28867a2013-03-26 15:42:39 -07003583 channel.dispose();
3584 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003585 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003586 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003587 return true;
Jeff Brownc28867a2013-03-26 15:42:39 -07003588 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003589 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003590
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003591 case MSG_START_INPUT: {
Yohei Yukawaf7526b52017-02-11 20:57:10 -08003592 final int missingMethods = msg.arg1;
3593 final boolean restarting = msg.arg2 != 0;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003594 args = (SomeArgs) msg.obj;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08003595 final IBinder startInputToken = (IBinder) args.arg1;
3596 final SessionState session = (SessionState) args.arg2;
3597 final IInputContext inputContext = (IInputContext) args.arg3;
3598 final EditorInfo editorInfo = (EditorInfo) args.arg4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003599 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003600 setEnabledSessionInMainThread(session);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08003601 session.method.startInput(startInputToken, inputContext, missingMethods,
Tarandeep Singheadb1392018-11-09 18:15:57 +01003602 editorInfo, restarting, session.client.shouldPreRenderIme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003603 } catch (RemoteException e) {
3604 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003605 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003606 return true;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003607 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003609 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003610
Yohei Yukawa33e81792015-11-17 21:14:42 -08003611 case MSG_UNBIND_CLIENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003612 try {
Yohei Yukawa33e81792015-11-17 21:14:42 -08003613 ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003614 } catch (RemoteException e) {
3615 // There is nothing interesting about the last client dying.
3616 }
3617 return true;
Yohei Yukawa33e81792015-11-17 21:14:42 -08003618 case MSG_BIND_CLIENT: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003619 args = (SomeArgs)msg.obj;
Jeff Brown1951ce82013-04-04 22:45:12 -07003620 IInputMethodClient client = (IInputMethodClient)args.arg1;
3621 InputBindResult res = (InputBindResult)args.arg2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003622 try {
Jeff Brown1951ce82013-04-04 22:45:12 -07003623 client.onBindMethod(res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003624 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003625 Slog.w(TAG, "Client died receiving input method " + args.arg2);
Jeff Brown1951ce82013-04-04 22:45:12 -07003626 } finally {
3627 // Dispose the channel if the input method is not local to this process
3628 // because the remote proxy will get its own copy when unparceled.
3629 if (res.channel != null && Binder.isProxy(client)) {
3630 res.channel.dispose();
3631 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003632 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003633 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003634 return true;
Jeff Brown1951ce82013-04-04 22:45:12 -07003635 }
Dianne Hackborna6e41342012-05-22 16:30:34 -07003636 case MSG_SET_ACTIVE:
3637 try {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003638 ((ClientState)msg.obj).client.setActive(msg.arg1 != 0, msg.arg2 != 0);
Dianne Hackborna6e41342012-05-22 16:30:34 -07003639 } catch (RemoteException e) {
3640 Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
3641 + ((ClientState)msg.obj).pid + " uid "
3642 + ((ClientState)msg.obj).uid);
3643 }
3644 return true;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003645 case MSG_SET_INTERACTIVE:
3646 handleSetInteractive(msg.arg1 != 0);
3647 return true;
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003648 case MSG_REPORT_FULLSCREEN_MODE: {
3649 final boolean fullscreen = msg.arg1 != 0;
3650 final ClientState clientState = (ClientState)msg.obj;
3651 try {
3652 clientState.client.reportFullscreenMode(fullscreen);
3653 } catch (RemoteException e) {
3654 Slog.w(TAG, "Got RemoteException sending "
3655 + "reportFullscreen(" + fullscreen + ") notification to pid="
3656 + clientState.pid + " uid=" + clientState.uid);
3657 }
3658 return true;
3659 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003660 case MSG_REPORT_PRE_RENDERED: {
3661 args = (SomeArgs) msg.obj;
3662 final EditorInfo info = (EditorInfo) args.arg1;
3663 final ClientState clientState = (ClientState) args.arg2;
3664 try {
3665 clientState.client.reportPreRendered(info);
3666 } catch (RemoteException e) {
3667 Slog.w(TAG, "Got RemoteException sending "
3668 + "reportPreRendered(" + info + ") notification to pid="
3669 + clientState.pid + " uid=" + clientState.uid);
3670 }
3671 args.recycle();
3672 return true;
3673 }
3674 case MSG_APPLY_IME_VISIBILITY: {
3675 final boolean setVisible = msg.arg1 != 0;
3676 final ClientState clientState = (ClientState) msg.obj;
3677 try {
3678 clientState.client.applyImeVisibility(setVisible);
3679 } catch (RemoteException e) {
3680 Slog.w(TAG, "Got RemoteException sending "
3681 + "applyImeVisibility(" + setVisible + ") notification to pid="
3682 + clientState.pid + " uid=" + clientState.uid);
3683 }
3684 return true;
3685 }
satok01038492012-04-09 21:08:27 +09003686
3687 // --------------------------------------------------------------
3688 case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
Michael Wright7b5a96b2014-08-09 19:28:42 -07003689 mHardKeyboardListener.handleHardKeyboardStatusChange(msg.arg1 == 1);
satok01038492012-04-09 21:08:27 +09003690 return true;
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07003691 case MSG_SYSTEM_UNLOCK_USER:
3692 final int userId = msg.arg1;
3693 onUnlockUser(userId);
3694 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003695 }
3696 return false;
3697 }
3698
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003699 private void handleSetInteractive(final boolean interactive) {
3700 synchronized (mMethodMap) {
3701 mIsInteractive = interactive;
Yohei Yukawa849443c2019-01-21 09:02:25 -08003702 updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003703
3704 // Inform the current client of the change in active status
3705 if (mCurClient != null && mCurClient.client != null) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003706 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
3707 MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mInFullscreenMode ? 1 : 0,
3708 mCurClient));
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003709 }
3710 }
3711 }
3712
satokdc9ddae2011-10-06 12:22:36 +09003713 private boolean chooseNewDefaultIMELocked() {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003714 final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
3715 mSettings.getEnabledInputMethodListLocked());
satokdc9ddae2011-10-06 12:22:36 +09003716 if (imi != null) {
satok03eb319a2010-11-11 18:17:42 +09003717 if (DEBUG) {
3718 Slog.d(TAG, "New default IME was selected: " + imi.getId());
3719 }
satok723a27e2010-11-11 14:58:11 +09003720 resetSelectedInputMethodAndSubtypeLocked(imi.getId());
Brandon Ballinger6da35a02009-10-21 00:38:13 -07003721 return true;
3722 }
3723
3724 return false;
3725 }
3726
Yohei Yukawa05139322018-12-25 10:34:14 -08003727 static void queryInputMethodServicesInternal(Context context,
3728 @UserIdInt int userId, ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap,
3729 ArrayMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList) {
3730 methodList.clear();
3731 methodMap.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003732
Yohei Yukawaed4952a2016-02-17 07:57:25 -08003733 // Note: We do not specify PackageManager.MATCH_ENCRYPTION_* flags here because the default
3734 // behavior of PackageManager is exactly what we want. It by default picks up appropriate
3735 // services depending on the unlock state for the specified user.
Yohei Yukawa05139322018-12-25 10:34:14 -08003736 final List<ResolveInfo> services = context.getPackageManager().queryIntentServicesAsUser(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003737 new Intent(InputMethod.SERVICE_INTERFACE),
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08003738 PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS,
Yohei Yukawa05139322018-12-25 10:34:14 -08003739 userId);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003740
Yohei Yukawa05139322018-12-25 10:34:14 -08003741 methodList.ensureCapacity(services.size());
3742 methodMap.ensureCapacity(services.size());
3743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003744 for (int i = 0; i < services.size(); ++i) {
3745 ResolveInfo ri = services.get(i);
3746 ServiceInfo si = ri.serviceInfo;
Yohei Yukawaddad4b92017-02-02 01:46:13 -08003747 final String imeId = InputMethodInfo.computeId(ri);
3748 if (!android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
3749 Slog.w(TAG, "Skipping input method " + imeId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003750 + ": it does not require the permission "
3751 + android.Manifest.permission.BIND_INPUT_METHOD);
3752 continue;
3753 }
3754
Yohei Yukawaddad4b92017-02-02 01:46:13 -08003755 if (DEBUG) Slog.d(TAG, "Checking " + imeId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003756
3757 try {
Yohei Yukawa05139322018-12-25 10:34:14 -08003758 final InputMethodInfo imi = new InputMethodInfo(context, ri,
3759 additionalSubtypeMap.get(imeId));
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08003760 if (imi.isVrOnly()) {
3761 continue; // Skip VR-only IME, which isn't supported for now.
3762 }
Yohei Yukawa05139322018-12-25 10:34:14 -08003763 methodList.add(imi);
3764 methodMap.put(imi.getId(), imi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003765 if (DEBUG) {
Yohei Yukawa05139322018-12-25 10:34:14 -08003766 Slog.d(TAG, "Found an input method " + imi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767 }
Tadashi G. Takaoka3c23d5b2016-09-16 11:41:07 +09003768 } catch (Exception e) {
Yohei Yukawaddad4b92017-02-02 01:46:13 -08003769 Slog.wtf(TAG, "Unable to load input method " + imeId, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003770 }
3771 }
Yohei Yukawa05139322018-12-25 10:34:14 -08003772 }
3773
3774 @GuardedBy("mMethodMap")
3775 void buildInputMethodListLocked(boolean resetDefaultEnabledIme) {
3776 if (DEBUG) {
3777 Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
3778 + " \n ------ caller=" + Debug.getCallers(10));
3779 }
3780 if (!mSystemReady) {
3781 Slog.e(TAG, "buildInputMethodListLocked is not allowed until system is ready");
3782 return;
3783 }
3784 mMethodMapUpdateCount++;
3785 mMyPackageMonitor.clearKnownImePackageNamesLocked();
3786
3787 queryInputMethodServicesInternal(mContext, mSettings.getCurrentUserId(),
Yohei Yukawab557d572018-12-29 21:26:26 -08003788 mAdditionalSubtypeMap, mMethodMap, mMethodList);
Brandon Ballinger6da35a02009-10-21 00:38:13 -07003789
Yohei Yukawac4e44912017-02-09 19:30:22 -08003790 // Construct the set of possible IME packages for onPackageChanged() to avoid false
3791 // negatives when the package state remains to be the same but only the component state is
3792 // changed.
3793 {
3794 // Here we intentionally use PackageManager.MATCH_DISABLED_COMPONENTS since the purpose
3795 // of this query is to avoid false negatives. PackageManager.MATCH_ALL could be more
3796 // conservative, but it seems we cannot use it for now (Issue 35176630).
Yohei Yukawa05139322018-12-25 10:34:14 -08003797 final List<ResolveInfo> allInputMethodServices =
3798 mContext.getPackageManager().queryIntentServicesAsUser(
3799 new Intent(InputMethod.SERVICE_INTERFACE),
3800 PackageManager.MATCH_DISABLED_COMPONENTS, mSettings.getCurrentUserId());
Yohei Yukawac4e44912017-02-09 19:30:22 -08003801 final int N = allInputMethodServices.size();
3802 for (int i = 0; i < N; ++i) {
3803 final ServiceInfo si = allInputMethodServices.get(i).serviceInfo;
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08003804 if (android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
3805 mMyPackageMonitor.addKnownImePackageNameLocked(si.packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08003806 }
Yohei Yukawac4e44912017-02-09 19:30:22 -08003807 }
3808 }
3809
Yohei Yukawa9c372192018-03-20 22:54:56 -07003810 boolean reenableMinimumNonAuxSystemImes = false;
Yohei Yukawa859df052016-02-17 07:56:46 -08003811 // TODO: The following code should find better place to live.
3812 if (!resetDefaultEnabledIme) {
3813 boolean enabledImeFound = false;
Yohei Yukawa9c372192018-03-20 22:54:56 -07003814 boolean enabledNonAuxImeFound = false;
Yohei Yukawa859df052016-02-17 07:56:46 -08003815 final List<InputMethodInfo> enabledImes = mSettings.getEnabledInputMethodListLocked();
3816 final int N = enabledImes.size();
3817 for (int i = 0; i < N; ++i) {
3818 final InputMethodInfo imi = enabledImes.get(i);
3819 if (mMethodList.contains(imi)) {
3820 enabledImeFound = true;
Yohei Yukawa9c372192018-03-20 22:54:56 -07003821 if (!imi.isAuxiliaryIme()) {
3822 enabledNonAuxImeFound = true;
3823 break;
3824 }
Yohei Yukawa859df052016-02-17 07:56:46 -08003825 }
3826 }
3827 if (!enabledImeFound) {
Yohei Yukawad0332832017-02-01 13:59:43 -08003828 if (DEBUG) {
3829 Slog.i(TAG, "All the enabled IMEs are gone. Reset default enabled IMEs.");
3830 }
Yohei Yukawa859df052016-02-17 07:56:46 -08003831 resetDefaultEnabledIme = true;
3832 resetSelectedInputMethodAndSubtypeLocked("");
Yohei Yukawa9c372192018-03-20 22:54:56 -07003833 } else if (!enabledNonAuxImeFound) {
3834 if (DEBUG) {
3835 Slog.i(TAG, "All the enabled non-Aux IMEs are gone. Do partial reset.");
3836 }
3837 reenableMinimumNonAuxSystemImes = true;
Yohei Yukawa859df052016-02-17 07:56:46 -08003838 }
3839 }
3840
Yohei Yukawa9c372192018-03-20 22:54:56 -07003841 if (resetDefaultEnabledIme || reenableMinimumNonAuxSystemImes) {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09003842 final ArrayList<InputMethodInfo> defaultEnabledIme =
Yohei Yukawa9c372192018-03-20 22:54:56 -07003843 InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList,
3844 reenableMinimumNonAuxSystemImes);
Yohei Yukawa68645a62016-02-17 07:54:20 -08003845 final int N = defaultEnabledIme.size();
3846 for (int i = 0; i < N; ++i) {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09003847 final InputMethodInfo imi = defaultEnabledIme.get(i);
3848 if (DEBUG) {
3849 Slog.d(TAG, "--- enable ime = " + imi);
3850 }
3851 setInputMethodEnabledLocked(imi.getId(), true);
3852 }
3853 }
3854
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003855 final String defaultImiId = mSettings.getSelectedInputMethod();
satok0a1bcf42012-05-16 19:26:31 +09003856 if (!TextUtils.isEmpty(defaultImiId)) {
Yohei Yukawa94e33302016-02-12 19:37:03 -08003857 if (!mMethodMap.containsKey(defaultImiId)) {
satok0a1bcf42012-05-16 19:26:31 +09003858 Slog.w(TAG, "Default IME is uninstalled. Choose new default IME.");
3859 if (chooseNewDefaultIMELocked()) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07003860 updateInputMethodsFromSettingsLocked(true);
satok0a1bcf42012-05-16 19:26:31 +09003861 }
3862 } else {
3863 // Double check that the default IME is certainly enabled.
3864 setInputMethodEnabledLocked(defaultImiId, true);
Brandon Ballinger6da35a02009-10-21 00:38:13 -07003865 }
3866 }
Yohei Yukawa3d46bab2014-05-30 18:10:18 +09003867 // Here is not the perfect place to reset the switching controller. Ideally
3868 // mSwitchingController and mSettings should be able to share the same state.
3869 // TODO: Make sure that mSwitchingController and mSettings are sharing the
3870 // the same enabled IMEs list.
Yohei Yukawac834a252014-05-21 22:42:32 +09003871 mSwitchingController.resetCircularListLocked(mContext);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003872 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003874 // ----------------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003875
satok217f5482010-12-15 05:19:19 +09003876 private void showInputMethodAndSubtypeEnabler(String inputMethodId) {
Tadashi G. Takaokaf49688f2011-01-20 17:56:13 +09003877 Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
satok47a44912010-10-06 16:03:58 +09003878 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
satok86417ea2010-10-27 14:11:03 +09003879 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
3880 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
satok7fee71f2010-12-17 18:54:26 +09003881 if (!TextUtils.isEmpty(inputMethodId)) {
Tadashi G. Takaoka25480202011-01-20 23:13:02 +09003882 intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
satok7fee71f2010-12-17 18:54:26 +09003883 }
Yohei Yukawa41f34272015-12-14 15:41:52 -08003884 final int userId;
3885 synchronized (mMethodMap) {
3886 userId = mSettings.getCurrentUserId();
3887 }
3888 mContext.startActivityAsUser(intent, null, UserHandle.of(userId));
satok217f5482010-12-15 05:19:19 +09003889 }
3890
3891 private void showConfigureInputMethods() {
3892 Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
3893 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
3894 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
3895 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Satoshi Kataoka3ba439d2012-10-05 18:30:13 +09003896 mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
satok47a44912010-10-06 16:03:58 +09003897 }
3898
satok2c93efc2012-04-02 19:33:47 +09003899 private boolean isScreenLocked() {
3900 return mKeyguardManager != null
3901 && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure();
3902 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003903
lumark0b05f9e2018-11-26 15:09:06 +08003904 private void showInputMethodMenu(boolean showAuxSubtypes, int displayId) {
Seigo Nonaka14e13912015-05-06 21:04:13 -07003905 if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003906
satok2c93efc2012-04-02 19:33:47 +09003907 final boolean isScreenLocked = isScreenLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003908
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003909 final String lastInputMethodId = mSettings.getSelectedInputMethod();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003910 int lastInputMethodSubtypeId = mSettings.getSelectedInputMethodSubtypeId(lastInputMethodId);
Joe Onorato8a9b2202010-02-26 18:56:32 -08003911 if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003912
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07003913 synchronized (mMethodMap) {
Yohei Yukawacf3bbff2018-11-20 17:24:20 -08003914 final List<ImeSubtypeListItem> imList =
3915 mSwitchingController.getSortedInputMethodAndSubtypeListLocked(
3916 showAuxSubtypes, isScreenLocked);
3917 if (imList.isEmpty()) {
satok7f35c8c2010-10-07 21:13:11 +09003918 return;
3919 }
3920
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07003921 hideInputMethodMenuLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003922
satokc3690562012-01-10 20:14:43 +09003923 if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003924 final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtypeLocked();
satokc3690562012-01-10 20:14:43 +09003925 if (currentSubtype != null) {
3926 final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003927 lastInputMethodSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
3928 currentImi, currentSubtype.hashCode());
satokc3690562012-01-10 20:14:43 +09003929 }
3930 }
3931
Ken Wakasa761eb372011-03-04 19:06:18 +09003932 final int N = imList.size();
satokab751aa2010-09-14 19:17:36 +09003933 mIms = new InputMethodInfo[N];
3934 mSubtypeIds = new int[N];
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07003935 int checkedItem = 0;
3936 for (int i = 0; i < N; ++i) {
Ken Wakasa05dbb652011-08-22 15:22:43 +09003937 final ImeSubtypeListItem item = imList.get(i);
3938 mIms[i] = item.mImi;
3939 mSubtypeIds[i] = item.mSubtypeId;
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07003940 if (mIms[i].getId().equals(lastInputMethodId)) {
satokab751aa2010-09-14 19:17:36 +09003941 int subtypeId = mSubtypeIds[i];
3942 if ((subtypeId == NOT_A_SUBTYPE_ID)
3943 || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0)
3944 || (subtypeId == lastInputMethodSubtypeId)) {
3945 checkedItem = i;
3946 }
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07003947 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003948 }
Alan Viverette505e3ab2014-11-24 15:22:11 -08003949
lumark0b05f9e2018-11-26 15:09:06 +08003950 final ActivityThread currentThread = ActivityThread.currentActivityThread();
Andrew Sapperstein8a3b4cb2017-04-28 14:35:31 -07003951 final Context settingsContext = new ContextThemeWrapper(
lumark0b05f9e2018-11-26 15:09:06 +08003952 displayId == DEFAULT_DISPLAY ? currentThread.getSystemUiContext()
3953 : currentThread.createSystemUiContext(displayId),
Alan Viverette505e3ab2014-11-24 15:22:11 -08003954 com.android.internal.R.style.Theme_DeviceDefault_Settings);
3955
3956 mDialogBuilder = new AlertDialog.Builder(settingsContext);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003957 mDialogBuilder.setOnCancelListener(new OnCancelListener() {
3958 @Override
3959 public void onCancel(DialogInterface dialog) {
3960 hideInputMethodMenu();
3961 }
3962 });
Alan Viverette505e3ab2014-11-24 15:22:11 -08003963
3964 final Context dialogContext = mDialogBuilder.getContext();
3965 final TypedArray a = dialogContext.obtainStyledAttributes(null,
3966 com.android.internal.R.styleable.DialogPreference,
3967 com.android.internal.R.attr.alertDialogStyle, 0);
3968 final Drawable dialogIcon = a.getDrawable(
3969 com.android.internal.R.styleable.DialogPreference_dialogIcon);
3970 a.recycle();
3971
3972 mDialogBuilder.setIcon(dialogIcon);
3973
Yohei Yukawad34e1482016-02-11 08:03:52 -08003974 final LayoutInflater inflater = dialogContext.getSystemService(LayoutInflater.class);
satok01038492012-04-09 21:08:27 +09003975 final View tv = inflater.inflate(
3976 com.android.internal.R.layout.input_method_switch_dialog_title, null);
3977 mDialogBuilder.setCustomTitle(tv);
3978
3979 // Setup layout for a toggle switch of the hardware keyboard
3980 mSwitchingDialogTitleView = tv;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003981 mSwitchingDialogTitleView
3982 .findViewById(com.android.internal.R.id.hard_keyboard_section)
Seigo Nonaka7309b122015-08-17 18:34:13 -07003983 .setVisibility(mWindowManagerInternal.isHardKeyboardAvailable()
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003984 ? View.VISIBLE : View.GONE);
Alan Viverette505e3ab2014-11-24 15:22:11 -08003985 final Switch hardKeySwitch = (Switch) mSwitchingDialogTitleView.findViewById(
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003986 com.android.internal.R.id.hard_keyboard_switch);
Michael Wright7b5a96b2014-08-09 19:28:42 -07003987 hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003988 hardKeySwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
3989 @Override
3990 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07003991 mSettings.setShowImeWithHardKeyboard(isChecked);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003992 // Ensure that the input method dialog is dismissed when changing
3993 // the hardware keyboard state.
3994 hideInputMethodMenu();
3995 }
3996 });
3997
Alan Viverette505e3ab2014-11-24 15:22:11 -08003998 final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(dialogContext,
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003999 com.android.internal.R.layout.input_method_switch_item, imList, checkedItem);
4000 final OnClickListener choiceListener = new OnClickListener() {
4001 @Override
4002 public void onClick(final DialogInterface dialog, final int which) {
4003 synchronized (mMethodMap) {
4004 if (mIms == null || mIms.length <= which || mSubtypeIds == null
4005 || mSubtypeIds.length <= which) {
4006 return;
satok01038492012-04-09 21:08:27 +09004007 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004008 final InputMethodInfo im = mIms[which];
4009 int subtypeId = mSubtypeIds[which];
4010 adapter.mCheckedItem = which;
4011 adapter.notifyDataSetChanged();
4012 hideInputMethodMenu();
4013 if (im != null) {
4014 if (subtypeId < 0 || subtypeId >= im.getSubtypeCount()) {
4015 subtypeId = NOT_A_SUBTYPE_ID;
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08004016 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004017 setInputMethodLocked(im.getId(), subtypeId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004018 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004019 }
4020 }
4021 };
4022 mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004023
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004024 mSwitchingDialog = mDialogBuilder.create();
Dianne Hackborne3a7f622011-03-03 21:48:24 -08004025 mSwitchingDialog.setCanceledOnTouchOutside(true);
Wale Ogunwale3a931692016-11-02 16:49:48 -07004026 final Window w = mSwitchingDialog.getWindow();
Yohei Yukawa6e875592019-01-28 00:49:30 -08004027 final LayoutParams attrs = w.getAttributes();
4028 w.setType(LayoutParams.TYPE_INPUT_METHOD_DIALOG);
Wale Ogunwale3a931692016-11-02 16:49:48 -07004029 // Use an alternate token for the dialog for that window manager can group the token
4030 // with other IME windows based on type vs. grouping based on whichever token happens
4031 // to get selected by the system later on.
4032 attrs.token = mSwitchingDialogToken;
Yohei Yukawa6e875592019-01-28 00:49:30 -08004033 attrs.privateFlags |= LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
Wale Ogunwale3a931692016-11-02 16:49:48 -07004034 attrs.setTitle("Select input method");
4035 w.setAttributes(attrs);
Yohei Yukawa849443c2019-01-21 09:02:25 -08004036 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004037 mSwitchingDialog.show();
4038 }
4039 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004040
Ken Wakasa05dbb652011-08-22 15:22:43 +09004041 private static class ImeSubtypeListAdapter extends ArrayAdapter<ImeSubtypeListItem> {
4042 private final LayoutInflater mInflater;
4043 private final int mTextViewResourceId;
4044 private final List<ImeSubtypeListItem> mItemsList;
Satoshi Kataokad2142962012-11-12 18:43:06 +09004045 public int mCheckedItem;
Ken Wakasa05dbb652011-08-22 15:22:43 +09004046 public ImeSubtypeListAdapter(Context context, int textViewResourceId,
4047 List<ImeSubtypeListItem> itemsList, int checkedItem) {
4048 super(context, textViewResourceId, itemsList);
Alan Viverette505e3ab2014-11-24 15:22:11 -08004049
Ken Wakasa05dbb652011-08-22 15:22:43 +09004050 mTextViewResourceId = textViewResourceId;
4051 mItemsList = itemsList;
4052 mCheckedItem = checkedItem;
Yohei Yukawad34e1482016-02-11 08:03:52 -08004053 mInflater = context.getSystemService(LayoutInflater.class);
Ken Wakasa05dbb652011-08-22 15:22:43 +09004054 }
4055
4056 @Override
4057 public View getView(int position, View convertView, ViewGroup parent) {
4058 final View view = convertView != null ? convertView
4059 : mInflater.inflate(mTextViewResourceId, null);
4060 if (position < 0 || position >= mItemsList.size()) return view;
4061 final ImeSubtypeListItem item = mItemsList.get(position);
4062 final CharSequence imeName = item.mImeName;
4063 final CharSequence subtypeName = item.mSubtypeName;
4064 final TextView firstTextView = (TextView)view.findViewById(android.R.id.text1);
4065 final TextView secondTextView = (TextView)view.findViewById(android.R.id.text2);
4066 if (TextUtils.isEmpty(subtypeName)) {
4067 firstTextView.setText(imeName);
4068 secondTextView.setVisibility(View.GONE);
4069 } else {
4070 firstTextView.setText(subtypeName);
4071 secondTextView.setText(imeName);
4072 secondTextView.setVisibility(View.VISIBLE);
4073 }
4074 final RadioButton radioButton =
4075 (RadioButton)view.findViewById(com.android.internal.R.id.radio);
4076 radioButton.setChecked(position == mCheckedItem);
4077 return view;
4078 }
4079 }
4080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004081 void hideInputMethodMenu() {
The Android Open Source Project10592532009-03-18 17:39:46 -07004082 synchronized (mMethodMap) {
4083 hideInputMethodMenuLocked();
4084 }
4085 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004086
The Android Open Source Project10592532009-03-18 17:39:46 -07004087 void hideInputMethodMenuLocked() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08004088 if (DEBUG) Slog.v(TAG, "Hide switching menu");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004089
The Android Open Source Project10592532009-03-18 17:39:46 -07004090 if (mSwitchingDialog != null) {
4091 mSwitchingDialog.dismiss();
4092 mSwitchingDialog = null;
Yohei Yukawa1fc7a1d2018-04-18 17:31:27 -07004093 mSwitchingDialogTitleView = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004094 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004095
Yohei Yukawa849443c2019-01-21 09:02:25 -08004096 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Project10592532009-03-18 17:39:46 -07004097 mDialogBuilder = null;
The Android Open Source Project10592532009-03-18 17:39:46 -07004098 mIms = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004099 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004101 // ----------------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004102
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004103 boolean setInputMethodEnabledLocked(String id, boolean enabled) {
4104 // Make sure this is a valid input method.
4105 InputMethodInfo imm = mMethodMap.get(id);
4106 if (imm == null) {
satokd87c2592010-09-29 11:52:06 +09004107 throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004108 }
4109
satokd87c2592010-09-29 11:52:06 +09004110 List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
4111 .getEnabledInputMethodsAndSubtypeListLocked();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004112
satokd87c2592010-09-29 11:52:06 +09004113 if (enabled) {
4114 for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
4115 if (pair.first.equals(id)) {
4116 // We are enabling this input method, but it is already enabled.
4117 // Nothing to do. The previous state was enabled.
4118 return true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004119 }
4120 }
satokd87c2592010-09-29 11:52:06 +09004121 mSettings.appendAndPutEnabledInputMethodLocked(id, false);
4122 // Previous state was disabled.
4123 return false;
4124 } else {
4125 StringBuilder builder = new StringBuilder();
4126 if (mSettings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
4127 builder, enabledInputMethodsList, id)) {
4128 // Disabled input method is currently selected, switch to another one.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004129 final String selId = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09004130 if (id.equals(selId) && !chooseNewDefaultIMELocked()) {
4131 Slog.i(TAG, "Can't find new IME, unsetting the current input method.");
4132 resetSelectedInputMethodAndSubtypeLocked("");
satokd87c2592010-09-29 11:52:06 +09004133 }
4134 // Previous state was enabled.
4135 return true;
4136 } else {
4137 // We are disabling the input method but it is already disabled.
4138 // Nothing to do. The previous state was disabled.
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004139 return false;
4140 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004141 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004142 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08004143
satok723a27e2010-11-11 14:58:11 +09004144 private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
4145 boolean setSubtypeOnly) {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004146 mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
Tarandeep Singh89a6c482017-11-21 14:26:11 -08004147
satok723a27e2010-11-11 14:58:11 +09004148 // Set Subtype here
4149 if (imi == null || subtypeId < 0) {
4150 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
Tadashi G. Takaoka0ba75bb2010-11-09 12:19:32 -08004151 mCurrentSubtype = null;
satok723a27e2010-11-11 14:58:11 +09004152 } else {
Ken Wakasa586f0512011-01-20 22:31:01 +09004153 if (subtypeId < imi.getSubtypeCount()) {
4154 InputMethodSubtype subtype = imi.getSubtypeAt(subtypeId);
4155 mSettings.putSelectedSubtype(subtype.hashCode());
4156 mCurrentSubtype = subtype;
satok723a27e2010-11-11 14:58:11 +09004157 } else {
4158 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
satokd81e9502012-05-21 12:58:45 +09004159 // If the subtype is not specified, choose the most applicable one
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004160 mCurrentSubtype = getCurrentInputMethodSubtypeLocked();
satok723a27e2010-11-11 14:58:11 +09004161 }
satokab751aa2010-09-14 19:17:36 +09004162 }
satok723a27e2010-11-11 14:58:11 +09004163
Yohei Yukawa68645a62016-02-17 07:54:20 -08004164 if (!setSubtypeOnly) {
satok723a27e2010-11-11 14:58:11 +09004165 // Set InputMethod here
4166 mSettings.putSelectedInputMethod(imi != null ? imi.getId() : "");
4167 }
4168 }
4169
4170 private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
4171 InputMethodInfo imi = mMethodMap.get(newDefaultIme);
4172 int lastSubtypeId = NOT_A_SUBTYPE_ID;
4173 // newDefaultIme is empty when there is no candidate for the selected IME.
4174 if (imi != null && !TextUtils.isEmpty(newDefaultIme)) {
4175 String subtypeHashCode = mSettings.getLastSubtypeForInputMethodLocked(newDefaultIme);
4176 if (subtypeHashCode != null) {
4177 try {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004178 lastSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
Narayan Kamatha09b4d22016-04-15 18:32:45 +01004179 imi, Integer.parseInt(subtypeHashCode));
satok723a27e2010-11-11 14:58:11 +09004180 } catch (NumberFormatException e) {
4181 Slog.w(TAG, "HashCode for subtype looks broken: " + subtypeHashCode, e);
4182 }
4183 }
4184 }
4185 setSelectedInputMethodAndSubtypeLocked(imi, lastSubtypeId, false);
satokab751aa2010-09-14 19:17:36 +09004186 }
4187
satokab751aa2010-09-14 19:17:36 +09004188 /**
4189 * @return Return the current subtype of this input method.
4190 */
satok42c5a162011-05-26 16:46:14 +09004191 @Override
satokab751aa2010-09-14 19:17:36 +09004192 public InputMethodSubtype getCurrentInputMethodSubtype() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004193 synchronized (mMethodMap) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08004194 // TODO: Make this work even for non-current users?
Yohei Yukawa46d74762019-01-22 10:17:22 -08004195 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08004196 return null;
4197 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004198 return getCurrentInputMethodSubtypeLocked();
4199 }
4200 }
4201
4202 private InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
satokfdf419e2012-05-08 16:52:08 +09004203 if (mCurMethodId == null) {
4204 return null;
4205 }
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004206 final boolean subtypeIsSelected = mSettings.isSubtypeSelected();
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004207 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
4208 if (imi == null || imi.getSubtypeCount() == 0) {
4209 return null;
satok4e4569d2010-11-19 18:45:53 +09004210 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004211 if (!subtypeIsSelected || mCurrentSubtype == null
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004212 || !InputMethodUtils.isValidSubtypeId(imi, mCurrentSubtype.hashCode())) {
4213 int subtypeId = mSettings.getSelectedInputMethodSubtypeId(mCurMethodId);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004214 if (subtypeId == NOT_A_SUBTYPE_ID) {
4215 // If there are no selected subtypes, the framework will try to find
4216 // the most applicable subtype from explicitly or implicitly enabled
4217 // subtypes.
4218 List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004219 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004220 // If there is only one explicitly or implicitly enabled subtype,
4221 // just returns it.
4222 if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
4223 mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
4224 } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004225 mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004226 mRes, explicitlyOrImplicitlyEnabledSubtypes,
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004227 InputMethodUtils.SUBTYPE_MODE_KEYBOARD, null, true);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004228 if (mCurrentSubtype == null) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004229 mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004230 mRes, explicitlyOrImplicitlyEnabledSubtypes, null, null,
4231 true);
satok4e4569d2010-11-19 18:45:53 +09004232 }
satok3ef8b292010-11-23 06:06:29 +09004233 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004234 } else {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004235 mCurrentSubtype = InputMethodUtils.getSubtypes(imi).get(subtypeId);
satok8fbb1e82010-11-02 23:15:58 +09004236 }
4237 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004238 return mCurrentSubtype;
satokab751aa2010-09-14 19:17:36 +09004239 }
4240
Yohei Yukawaa878b952019-01-10 19:36:24 -08004241 private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
4242 synchronized (mMethodMap) {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004243 return getInputMethodListLocked(userId);
Yohei Yukawaa878b952019-01-10 19:36:24 -08004244 }
4245 }
4246
4247 private List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
4248 synchronized (mMethodMap) {
4249 return getEnabledInputMethodListLocked(userId);
4250 }
4251 }
4252
Yohei Yukawae24ed792018-08-28 19:10:32 -07004253 private static final class LocalServiceImpl extends InputMethodManagerInternal {
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004254 @NonNull
Yohei Yukawafffc0e52018-09-04 13:24:00 -07004255 private final InputMethodManagerService mService;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004256
Yohei Yukawafffc0e52018-09-04 13:24:00 -07004257 LocalServiceImpl(@NonNull InputMethodManagerService service) {
4258 mService = service;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004259 }
4260
4261 @Override
4262 public void setInteractive(boolean interactive) {
4263 // Do everything in handler so as not to block the caller.
Yohei Yukawaf16abb72018-09-05 11:28:42 -07004264 mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0)
4265 .sendToTarget();
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004266 }
Yohei Yukawaae61f712015-12-09 13:00:10 -08004267
4268 @Override
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07004269 public void hideCurrentInputMethod() {
Yohei Yukawaf16abb72018-09-05 11:28:42 -07004270 mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
4271 mService.mHandler.sendEmptyMessage(MSG_HIDE_CURRENT_INPUT_METHOD);
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07004272 }
Tarandeep Singh89a6c482017-11-21 14:26:11 -08004273
4274 @Override
Yohei Yukawaa878b952019-01-10 19:36:24 -08004275 public List<InputMethodInfo> getInputMethodListAsUser(int userId) {
4276 return mService.getInputMethodListAsUser(userId);
4277 }
4278
4279 @Override
4280 public List<InputMethodInfo> getEnabledInputMethodListAsUser(int userId) {
4281 return mService.getEnabledInputMethodListAsUser(userId);
4282 }
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004283 }
4284
Yohei Yukawac54c1172018-09-06 11:39:50 -07004285 @BinderThread
4286 private IInputContentUriToken createInputContentUriToken(@Nullable IBinder token,
Yohei Yukawa25e08132016-06-22 16:31:41 -07004287 @Nullable Uri contentUri, @Nullable String packageName) {
Yohei Yukawa25e08132016-06-22 16:31:41 -07004288 if (token == null) {
4289 throw new NullPointerException("token");
4290 }
4291 if (packageName == null) {
4292 throw new NullPointerException("packageName");
4293 }
4294 if (contentUri == null) {
4295 throw new NullPointerException("contentUri");
4296 }
4297 final String contentUriScheme = contentUri.getScheme();
4298 if (!"content".equals(contentUriScheme)) {
4299 throw new InvalidParameterException("contentUri must have content scheme");
4300 }
4301
4302 synchronized (mMethodMap) {
4303 final int uid = Binder.getCallingUid();
4304 if (mCurMethodId == null) {
4305 return null;
4306 }
4307 if (mCurToken != token) {
4308 Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + mCurToken
4309 + " token=" + token);
4310 return null;
4311 }
4312 // We cannot simply distinguish a bad IME that reports an arbitrary package name from
4313 // an unfortunate IME whose internal state is already obsolete due to the asynchronous
4314 // nature of our system. Let's compare it with our internal record.
4315 if (!TextUtils.equals(mCurAttribute.packageName, packageName)) {
4316 Slog.e(TAG, "Ignoring createInputContentUriToken mCurAttribute.packageName="
4317 + mCurAttribute.packageName + " packageName=" + packageName);
4318 return null;
4319 }
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004320 // This user ID can never bee spoofed.
Yohei Yukawa25e08132016-06-22 16:31:41 -07004321 final int imeUserId = UserHandle.getUserId(uid);
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004322 // This user ID can never bee spoofed.
Yohei Yukawa25e08132016-06-22 16:31:41 -07004323 final int appUserId = UserHandle.getUserId(mCurClient.uid);
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004324 // This user ID may be invalid if "contentUri" embedded an invalid user ID.
4325 final int contentUriOwnerUserId = ContentProvider.getUserIdFromUri(contentUri,
4326 imeUserId);
4327 final Uri contentUriWithoutUserId = ContentProvider.getUriWithoutUserId(contentUri);
4328 // Note: InputContentUriTokenHandler.take() checks whether the IME (specified by "uid")
4329 // actually has the right to grant a read permission for "contentUriWithoutUserId" that
4330 // is claimed to belong to "contentUriOwnerUserId". For example, specifying random
4331 // content URI and/or contentUriOwnerUserId just results in a SecurityException thrown
4332 // from InputContentUriTokenHandler.take() and can never be allowed beyond what is
4333 // actually allowed to "uid", which is guaranteed to be the IME's one.
4334 return new InputContentUriTokenHandler(contentUriWithoutUserId, uid,
4335 packageName, contentUriOwnerUserId, appUserId);
Yohei Yukawa25e08132016-06-22 16:31:41 -07004336 }
4337 }
4338
Yohei Yukawac54c1172018-09-06 11:39:50 -07004339 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08004340 private void reportFullscreenMode(@NonNull IBinder token, boolean fullscreen) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004341 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08004342 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004343 return;
4344 }
4345 if (mCurClient != null && mCurClient.client != null) {
4346 mInFullscreenMode = fullscreen;
4347 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
4348 MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, mCurClient));
4349 }
4350 }
4351 }
4352
4353 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004354 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06004355 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004356
4357 IInputMethod method;
4358 ClientState client;
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004359 ClientState focusedWindowClient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004361 final Printer p = new PrintWriterPrinter(pw);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004363 synchronized (mMethodMap) {
4364 p.println("Current Input Method Manager state:");
4365 int N = mMethodList.size();
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08004366 p.println(" Input Methods: mMethodMapUpdateCount=" + mMethodMapUpdateCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004367 for (int i=0; i<N; i++) {
4368 InputMethodInfo info = mMethodList.get(i);
4369 p.println(" InputMethod #" + i + ":");
4370 info.dump(p, " ");
4371 }
4372 p.println(" Clients:");
Yohei Yukawaac9311e2018-11-20 19:25:23 -08004373 final int numClients = mClients.size();
4374 for (int i = 0; i < numClients; ++i) {
4375 final ClientState ci = mClients.valueAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004376 p.println(" Client " + ci + ":");
4377 p.println(" client=" + ci.client);
4378 p.println(" inputContext=" + ci.inputContext);
4379 p.println(" sessionRequested=" + ci.sessionRequested);
4380 p.println(" curSession=" + ci.curSession);
4381 }
The Android Open Source Project10592532009-03-18 17:39:46 -07004382 p.println(" mCurMethodId=" + mCurMethodId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004383 client = mCurClient;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07004384 p.println(" mCurClient=" + client + " mCurSeq=" + mCurSeq);
Yohei Yukawa22a89232017-02-12 16:38:59 -08004385 p.println(" mCurFocusedWindow=" + mCurFocusedWindow
4386 + " softInputMode=" +
Yohei Yukawaa468d702018-10-21 11:42:34 -07004387 InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode)
Yohei Yukawa22a89232017-02-12 16:38:59 -08004388 + " client=" + mCurFocusedWindowClient);
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004389 focusedWindowClient = mCurFocusedWindowClient;
Yohei Yukawad3ef8422018-06-07 16:28:07 -07004390 p.println(" mCurId=" + mCurId + " mHaveConnection=" + mHaveConnection
4391 + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + mVisibleBound);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004392 p.println(" mCurToken=" + mCurToken);
lumark90120a82018-08-15 00:33:03 +08004393 p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004394 p.println(" mCurIntent=" + mCurIntent);
4395 method = mCurMethod;
4396 p.println(" mCurMethod=" + mCurMethod);
4397 p.println(" mEnabledSession=" + mEnabledSession);
4398 p.println(" mShowRequested=" + mShowRequested
4399 + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
4400 + " mShowForced=" + mShowForced
4401 + " mInputShown=" + mInputShown);
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004402 p.println(" mInFullscreenMode=" + mInFullscreenMode);
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004403 p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
Yohei Yukawa81482972015-06-04 00:58:59 -07004404 p.println(" mSettingsObserver=" + mSettingsObserver);
Yohei Yukawad7248862015-06-03 23:56:12 -07004405 p.println(" mSwitchingController:");
4406 mSwitchingController.dump(p);
Yohei Yukawa68645a62016-02-17 07:54:20 -08004407 p.println(" mSettings:");
4408 mSettings.dumpLocked(p, " ");
Yohei Yukawa357b2f62017-02-14 09:40:03 -08004409
4410 p.println(" mStartInputHistory:");
4411 mStartInputHistory.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004412 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004413
Jeff Brownb88102f2010-09-08 11:49:43 -07004414 p.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004415 if (client != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004416 pw.flush();
4417 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07004418 TransferPipe.dumpAsync(client.client.asBinder(), fd, args);
4419 } catch (IOException | RemoteException e) {
4420 p.println("Failed to dump input method client: " + e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004421 }
Jeff Brownb88102f2010-09-08 11:49:43 -07004422 } else {
4423 p.println("No input method client.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004424 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004425
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004426 if (focusedWindowClient != null && client != focusedWindowClient) {
4427 p.println(" ");
4428 p.println("Warning: Current input method client doesn't match the last focused. "
4429 + "window.");
4430 p.println("Dumping input method client in the last focused window just in case.");
4431 p.println(" ");
4432 pw.flush();
4433 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07004434 TransferPipe.dumpAsync(focusedWindowClient.client.asBinder(), fd, args);
4435 } catch (IOException | RemoteException e) {
4436 p.println("Failed to dump input method client in focused window: " + e);
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004437 }
4438 }
4439
Jeff Brownb88102f2010-09-08 11:49:43 -07004440 p.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004441 if (method != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004442 pw.flush();
4443 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07004444 TransferPipe.dumpAsync(method.asBinder(), fd, args);
4445 } catch (IOException | RemoteException e) {
4446 p.println("Failed to dump input method service: " + e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004447 }
Jeff Brownb88102f2010-09-08 11:49:43 -07004448 } else {
4449 p.println("No input method service.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004450 }
4451 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004452
4453 @BinderThread
4454 @Override
4455 public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
4456 @Nullable FileDescriptor err,
4457 @NonNull String[] args, @Nullable ShellCallback callback,
4458 @NonNull ResultReceiver resultReceiver) throws RemoteException {
Yohei Yukawab8d240f2018-12-26 10:03:11 -08004459 final int callingUid = Binder.getCallingUid();
4460 // Reject any incoming calls from non-shell users, including ones from the system user.
4461 if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) {
4462 // Note that Binder#onTransact() will automatically close "in", "out", and "err" when
4463 // returned from this method, hence there is no need to close those FDs.
4464 // "resultReceiver" is the only thing that needs to be taken care of here.
4465 if (resultReceiver != null) {
4466 resultReceiver.send(ShellCommandResult.FAILURE, null);
4467 }
4468 final String errorMsg = "InputMethodManagerService does not support shell commands from"
4469 + " non-shell users. callingUid=" + callingUid
4470 + " args=" + Arrays.toString(args);
4471 if (Process.isCoreUid(callingUid)) {
4472 // Let's not crash the calling process if the caller is one of core components.
4473 Slog.e(TAG, errorMsg);
4474 return;
4475 }
4476 throw new SecurityException(errorMsg);
4477 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004478 new ShellCommandImpl(this).exec(
4479 this, in, out, err, args, callback, resultReceiver);
4480 }
4481
4482 private static final class ShellCommandImpl extends ShellCommand {
4483 @NonNull
4484 final InputMethodManagerService mService;
4485
4486 ShellCommandImpl(InputMethodManagerService service) {
4487 mService = service;
4488 }
4489
Yohei Yukawadb25df72018-12-27 08:40:41 -08004490 @RequiresPermission(allOf = {
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004491 Manifest.permission.DUMP,
4492 Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Yohei Yukawadb25df72018-12-27 08:40:41 -08004493 Manifest.permission.WRITE_SECURE_SETTINGS,
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004494 })
Yohei Yukawa926488d2017-12-11 17:24:55 -08004495 @BinderThread
4496 @ShellCommandResult
4497 @Override
4498 public int onCommand(@Nullable String cmd) {
Yohei Yukawadb25df72018-12-27 08:40:41 -08004499 // For shell command, require all the permissions here in favor of code simplicity.
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004500 Arrays.asList(
4501 Manifest.permission.DUMP,
4502 Manifest.permission.INTERACT_ACROSS_USERS_FULL,
4503 Manifest.permission.WRITE_SECURE_SETTINGS
4504 ).forEach(permission -> mService.mContext.enforceCallingPermission(permission, null));
Yohei Yukawadb25df72018-12-27 08:40:41 -08004505
4506 final long identity = Binder.clearCallingIdentity();
4507 try {
4508 return onCommandWithSystemIdentity(cmd);
4509 } finally {
4510 Binder.restoreCallingIdentity(identity);
4511 }
4512 }
4513
4514 @BinderThread
4515 @ShellCommandResult
4516 private int onCommandWithSystemIdentity(@Nullable String cmd) {
Yohei Yukawadfdab732018-02-21 07:16:30 +09004517 if ("refresh_debug_properties".equals(cmd)) {
4518 return refreshDebugProperties();
4519 }
4520
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08004521 if ("get-last-switch-user-id".equals(cmd)) {
4522 return mService.getLastSwitchUserId(this);
4523 }
4524
Yohei Yukawacac97722017-12-15 16:52:05 -08004525 // For existing "adb shell ime <command>".
4526 if ("ime".equals(cmd)) {
4527 final String imeCommand = getNextArg();
4528 if (imeCommand == null || "help".equals(imeCommand) || "-h".equals(imeCommand)) {
4529 onImeCommandHelp();
4530 return ShellCommandResult.SUCCESS;
4531 }
4532 switch (imeCommand) {
4533 case "list":
4534 return mService.handleShellCommandListInputMethods(this);
4535 case "enable":
4536 return mService.handleShellCommandEnableDisableInputMethod(this, true);
4537 case "disable":
4538 return mService.handleShellCommandEnableDisableInputMethod(this, false);
4539 case "set":
4540 return mService.handleShellCommandSetInputMethod(this);
4541 case "reset":
4542 return mService.handleShellCommandResetInputMethod(this);
4543 default:
4544 getOutPrintWriter().println("Unknown command: " + imeCommand);
4545 return ShellCommandResult.FAILURE;
4546 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004547 }
Yohei Yukawacac97722017-12-15 16:52:05 -08004548
4549 return handleDefaultCommands(cmd);
Yohei Yukawa926488d2017-12-11 17:24:55 -08004550 }
4551
4552 @BinderThread
Tarandeep Singh75a92392018-01-12 14:58:59 -08004553 @ShellCommandResult
4554 private int refreshDebugProperties() {
4555 DebugFlags.FLAG_OPTIMIZE_START_INPUT.refresh();
Tarandeep Singheadb1392018-11-09 18:15:57 +01004556 DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.refresh();
Tarandeep Singh75a92392018-01-12 14:58:59 -08004557 return ShellCommandResult.SUCCESS;
4558 }
4559
4560 @BinderThread
Yohei Yukawa926488d2017-12-11 17:24:55 -08004561 @Override
4562 public void onHelp() {
4563 try (PrintWriter pw = getOutPrintWriter()) {
4564 pw.println("InputMethodManagerService commands:");
4565 pw.println(" help");
4566 pw.println(" Prints this help text.");
4567 pw.println(" dump [options]");
4568 pw.println(" Synonym of dumpsys.");
Yohei Yukawacac97722017-12-15 16:52:05 -08004569 pw.println(" ime <command> [options]");
4570 pw.println(" Manipulate IMEs. Run \"ime help\" for details.");
4571 }
4572 }
4573
4574 private void onImeCommandHelp() {
4575 try (IndentingPrintWriter pw =
4576 new IndentingPrintWriter(getOutPrintWriter(), " ", 100)) {
4577 pw.println("ime <command>:");
4578 pw.increaseIndent();
4579
4580 pw.println("list [-a] [-s]");
4581 pw.increaseIndent();
4582 pw.println("prints all enabled input methods.");
4583 pw.increaseIndent();
4584 pw.println("-a: see all input methods");
4585 pw.println("-s: only a single summary line of each");
4586 pw.decreaseIndent();
4587 pw.decreaseIndent();
4588
4589 pw.println("enable <ID>");
4590 pw.increaseIndent();
4591 pw.println("allows the given input method ID to be used.");
4592 pw.decreaseIndent();
4593
4594 pw.println("disable <ID>");
4595 pw.increaseIndent();
4596 pw.println("disallows the given input method ID to be used.");
4597 pw.decreaseIndent();
4598
4599 pw.println("set <ID>");
4600 pw.increaseIndent();
4601 pw.println("switches to the given input method ID.");
4602 pw.decreaseIndent();
4603
4604 pw.println("reset");
4605 pw.increaseIndent();
4606 pw.println("reset currently selected/enabled IMEs to the default ones as if "
4607 + "the device is initially booted with the current locale.");
4608 pw.decreaseIndent();
4609
4610 pw.decreaseIndent();
Yohei Yukawa926488d2017-12-11 17:24:55 -08004611 }
4612 }
4613 }
4614
4615 // ----------------------------------------------------------------------
4616 // Shell command handlers:
4617
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08004618 @BinderThread
4619 @ShellCommandResult
4620 private int getLastSwitchUserId(@NonNull ShellCommand shellCommand) {
4621 synchronized (mMethodMap) {
4622 shellCommand.getOutPrintWriter().println(mLastSwitchUserId);
4623 return ShellCommandResult.SUCCESS;
4624 }
4625 }
4626
Yohei Yukawa926488d2017-12-11 17:24:55 -08004627 /**
4628 * Handles {@code adb shell ime list}.
4629 * @param shellCommand {@link ShellCommand} object that is handling this command.
4630 * @return Exit code of the command.
4631 */
4632 @BinderThread
4633 @ShellCommandResult
4634 private int handleShellCommandListInputMethods(@NonNull ShellCommand shellCommand) {
4635 boolean all = false;
4636 boolean brief = false;
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004637 int userIdToBeResolved = UserHandle.USER_CURRENT;
Yohei Yukawa926488d2017-12-11 17:24:55 -08004638 while (true) {
4639 final String nextOption = shellCommand.getNextOption();
4640 if (nextOption == null) {
4641 break;
4642 }
4643 switch (nextOption) {
4644 case "-a":
4645 all = true;
4646 break;
4647 case "-s":
4648 brief = true;
4649 break;
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004650 case "-u":
4651 case "--user":
4652 userIdToBeResolved = UserHandle.parseUserArg(shellCommand.getNextArgRequired());
4653 break;
Yohei Yukawa926488d2017-12-11 17:24:55 -08004654 }
4655 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004656 synchronized (mMethodMap) {
4657 final PrintWriter pr = shellCommand.getOutPrintWriter();
4658 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
4659 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
4660 for (int userId : userIds) {
4661 final List<InputMethodInfo> methods = all
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004662 ? getInputMethodListLocked(userId)
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004663 : getEnabledInputMethodListLocked(userId);
4664 if (userIds.length > 1) {
4665 pr.print("User #");
4666 pr.print(userId);
4667 pr.println(":");
4668 }
4669 for (InputMethodInfo info : methods) {
4670 if (brief) {
4671 pr.println(info.getId());
4672 } else {
4673 pr.print(info.getId());
4674 pr.println(":");
4675 info.dump(pr::println, " ");
4676 }
4677 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004678 }
4679 }
4680 return ShellCommandResult.SUCCESS;
4681 }
4682
4683 /**
4684 * Handles {@code adb shell ime enable} and {@code adb shell ime disable}.
4685 * @param shellCommand {@link ShellCommand} object that is handling this command.
4686 * @param enabled {@code true} if the command was {@code adb shell ime enable}.
4687 * @return Exit code of the command.
4688 */
4689 @BinderThread
4690 @ShellCommandResult
Yohei Yukawa926488d2017-12-11 17:24:55 -08004691 private int handleShellCommandEnableDisableInputMethod(
4692 @NonNull ShellCommand shellCommand, boolean enabled) {
Yohei Yukawa926488d2017-12-11 17:24:55 -08004693 final String id = shellCommand.getNextArgRequired();
Yohei Yukawa926488d2017-12-11 17:24:55 -08004694 final boolean previouslyEnabled;
4695 synchronized (mMethodMap) {
Tarandeep Singh87e2e512019-03-06 14:28:52 -08004696 if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
4697 return ShellCommandResult.SUCCESS;
4698 }
Yohei Yukawadb25df72018-12-27 08:40:41 -08004699 previouslyEnabled = setInputMethodEnabledLocked(id, enabled);
Yohei Yukawa926488d2017-12-11 17:24:55 -08004700 }
4701 final PrintWriter pr = shellCommand.getOutPrintWriter();
4702 pr.print("Input method ");
4703 pr.print(id);
4704 pr.print(": ");
4705 pr.print((enabled == previouslyEnabled) ? "already " : "now ");
4706 pr.println(enabled ? "enabled" : "disabled");
4707 return ShellCommandResult.SUCCESS;
4708 }
4709
4710 /**
4711 * Handles {@code adb shell ime set}.
4712 * @param shellCommand {@link ShellCommand} object that is handling this command.
4713 * @return Exit code of the command.
4714 */
4715 @BinderThread
4716 @ShellCommandResult
4717 private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) {
4718 final String id = shellCommand.getNextArgRequired();
Yohei Yukawadb25df72018-12-27 08:40:41 -08004719 synchronized (mMethodMap) {
Tarandeep Singh87e2e512019-03-06 14:28:52 -08004720 if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
4721 return ShellCommandResult.SUCCESS;
4722 }
Yohei Yukawadb25df72018-12-27 08:40:41 -08004723 setInputMethodLocked(id, NOT_A_SUBTYPE_ID);
4724 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004725 final PrintWriter pr = shellCommand.getOutPrintWriter();
4726 pr.print("Input method ");
4727 pr.print(id);
4728 pr.println(" selected");
4729 return ShellCommandResult.SUCCESS;
4730 }
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08004731
4732 /**
4733 * Handles {@code adb shell ime reset-ime}.
4734 * @param shellCommand {@link ShellCommand} object that is handling this command.
4735 * @return Exit code of the command.
4736 */
4737 @BinderThread
4738 @ShellCommandResult
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08004739 private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08004740 synchronized (mMethodMap) {
Tarandeep Singh87e2e512019-03-06 14:28:52 -08004741 if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
4742 return ShellCommandResult.SUCCESS;
4743 }
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08004744 final String nextIme;
4745 final List<InputMethodInfo> nextEnabledImes;
Yohei Yukawadb25df72018-12-27 08:40:41 -08004746 hideCurrentInputLocked(0, null);
4747 unbindCurrentMethodLocked();
4748 // Reset the current IME
4749 resetSelectedInputMethodAndSubtypeLocked(null);
4750 // Also reset the settings of the current IME
4751 mSettings.putSelectedInputMethod(null);
4752 // Disable all enabled IMEs.
4753 mSettings.getEnabledInputMethodListLocked().forEach(
4754 imi -> setInputMethodEnabledLocked(imi.getId(), false));
4755 // Re-enable with default enabled IMEs.
4756 InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList).forEach(
4757 imi -> setInputMethodEnabledLocked(imi.getId(), true));
4758 updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
4759 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
4760 mSettings.getEnabledInputMethodListLocked(),
4761 mSettings.getCurrentUserId(),
4762 mContext.getBasePackageName());
4763 nextIme = mSettings.getSelectedInputMethod();
Yohei Yukawa9cd0c8a2019-02-04 22:25:24 -08004764 nextEnabledImes = mSettings.getEnabledInputMethodListLocked();
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08004765 final PrintWriter pr = shellCommand.getOutPrintWriter();
4766 pr.println("Reset current and enabled IMEs");
4767 pr.println("Newly selected IME:");
4768 pr.print(" "); pr.println(nextIme);
4769 pr.println("Newly enabled IMEs:");
4770 {
4771 final int N = nextEnabledImes.size();
4772 for (int i = 0; i < N; ++i) {
4773 pr.print(" ");
4774 pr.println(nextEnabledImes.get(i).getId());
4775 }
4776 }
4777 return ShellCommandResult.SUCCESS;
4778 }
4779 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07004780
Tarandeep Singh87e2e512019-03-06 14:28:52 -08004781 /**
4782 * @param userId the actual user handle obtained by {@link UserHandle#getIdentifier()}
4783 * and *not* pseudo ids like {@link UserHandle#USER_ALL etc}.
4784 * @return {@code true} if userId has debugging privileges.
4785 * i.e. {@link UserManager#DISALLOW_DEBUGGING_FEATURES} is {@code false}.
4786 */
4787 private boolean userHasDebugPriv(int userId, final ShellCommand shellCommand) {
4788 if (mUserManager.hasUserRestriction(
4789 UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(userId))) {
4790 shellCommand.getErrPrintWriter().println("User #" + userId
4791 + " is restricted with DISALLOW_DEBUGGING_FEATURES.");
4792 return false;
4793 }
4794 return true;
4795 }
4796
Yohei Yukawac54c1172018-09-06 11:39:50 -07004797 private static final class InputMethodPrivilegedOperationsImpl
4798 extends IInputMethodPrivilegedOperations.Stub {
4799 private final InputMethodManagerService mImms;
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08004800 @NonNull
Yohei Yukawac54c1172018-09-06 11:39:50 -07004801 private final IBinder mToken;
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08004802 InputMethodPrivilegedOperationsImpl(InputMethodManagerService imms,
4803 @NonNull IBinder token) {
Yohei Yukawac54c1172018-09-06 11:39:50 -07004804 mImms = imms;
4805 mToken = token;
4806 }
4807
4808 @BinderThread
4809 @Override
4810 public void setImeWindowStatus(int vis, int backDisposition) {
4811 mImms.setImeWindowStatus(mToken, vis, backDisposition);
4812 }
4813
4814 @BinderThread
4815 @Override
4816 public void reportStartInput(IBinder startInputToken) {
4817 mImms.reportStartInput(mToken, startInputToken);
4818 }
4819
4820 @BinderThread
4821 @Override
Yohei Yukawac54c1172018-09-06 11:39:50 -07004822 public IInputContentUriToken createInputContentUriToken(Uri contentUri,
4823 String packageName) {
4824 return mImms.createInputContentUriToken(mToken, contentUri, packageName);
4825 }
4826
4827 @BinderThread
4828 @Override
4829 public void reportFullscreenMode(boolean fullscreen) {
4830 mImms.reportFullscreenMode(mToken, fullscreen);
4831 }
Yohei Yukawac7ca3682018-09-09 20:48:38 -07004832
4833 @BinderThread
4834 @Override
4835 public void setInputMethod(String id) {
4836 mImms.setInputMethod(mToken, id);
4837 }
4838
4839 @BinderThread
4840 @Override
4841 public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
4842 mImms.setInputMethodAndSubtype(mToken, id, subtype);
4843 }
4844
4845 @BinderThread
4846 @Override
4847 public void hideMySoftInput(int flags) {
4848 mImms.hideMySoftInput(mToken, flags);
4849 }
4850
4851 @BinderThread
4852 @Override
4853 public void showMySoftInput(int flags) {
4854 mImms.showMySoftInput(mToken, flags);
4855 }
4856
4857 @BinderThread
4858 @Override
Yohei Yukawa41b094f2018-09-09 23:58:45 -07004859 public void updateStatusIcon(String packageName, @DrawableRes int iconId) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07004860 mImms.updateStatusIcon(mToken, packageName, iconId);
4861 }
4862
4863 @BinderThread
4864 @Override
4865 public boolean switchToPreviousInputMethod() {
4866 return mImms.switchToPreviousInputMethod(mToken);
4867 }
4868
4869 @BinderThread
4870 @Override
4871 public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
4872 return mImms.switchToNextInputMethod(mToken, onlyCurrentIme);
4873 }
4874
4875 @BinderThread
4876 @Override
4877 public boolean shouldOfferSwitchingToNextInputMethod() {
4878 return mImms.shouldOfferSwitchingToNextInputMethod(mToken);
4879 }
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07004880
4881 @BinderThread
4882 @Override
Yohei Yukawa9b60ba02019-01-21 00:06:27 -08004883 public void notifyUserAction() {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07004884 mImms.notifyUserAction(mToken);
4885 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08004886
4887 @BinderThread
4888 @Override
4889 public void reportPreRendered(EditorInfo info) {
4890 mImms.reportPreRendered(mToken, info);
4891 }
4892
4893 @BinderThread
4894 @Override
4895 public void applyImeVisibility(boolean setVisible) {
4896 mImms.applyImeVisibility(mToken, setVisible);
4897 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07004898 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004899}