blob: 96ba0841855c2d27f4ac92951292be0c12130cc4 [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;
lumarkef1965b2018-09-12 17:42:53 +080067import android.hardware.display.DisplayManagerInternal;
Joe Onorato857fd9b2011-01-27 15:08:35 -080068import android.inputmethodservice.InputMethodService;
Michael Wright7b5a96b2014-08-09 19:28:42 -070069import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.os.Binder;
Chris Wren1ce4b6d2015-06-11 10:19:43 -040071import android.os.Bundle;
Seigo Nonakae27dc2b2015-08-14 18:21:27 -070072import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Handler;
74import android.os.IBinder;
75import android.os.IInterface;
Yohei Yukawa23cbe852016-05-17 16:42:58 -070076import android.os.LocaleList;
Yohei Yukawa0569a182018-08-28 16:09:28 -070077import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import android.os.Parcel;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070079import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import android.os.RemoteException;
The Android Open Source Project4df24232009-03-05 14:34:35 -080081import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import android.os.ServiceManager;
Yohei Yukawa926488d2017-12-11 17:24:55 -080083import android.os.ShellCallback;
84import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.SystemClock;
Tarandeep Singh75a92392018-01-12 14:58:59 -080086import android.os.SystemProperties;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +090087import android.os.UserHandle;
Amith Yamasani734983f2014-03-04 16:48:05 -080088import android.os.UserManager;
Yohei Yukawa42081402019-01-15 09:57:50 -080089import android.os.UserManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.provider.Settings;
91import android.text.TextUtils;
satokf9f01002011-05-19 21:31:50 +090092import android.text.style.SuggestionSpan;
Yohei Yukawaac9311e2018-11-20 19:25:23 -080093import android.util.ArrayMap;
Christopher Tate7b9a28c2015-03-18 13:06:16 -070094import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.util.EventLog;
satokf9f01002011-05-19 21:31:50 +090096import android.util.LruCache;
satokab751aa2010-09-14 19:17:36 +090097import android.util.Pair;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098import android.util.PrintWriterPrinter;
99import android.util.Printer;
satoke7c6998e2011-06-03 17:57:59 +0900100import android.util.Slog;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +0900101import android.view.ContextThemeWrapper;
lumarkef1965b2018-09-12 17:42:53 +0800102import android.view.Display;
103import android.view.DisplayInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104import android.view.IWindowManager;
Jeff Brownc28867a2013-03-26 15:42:39 -0700105import android.view.InputChannel;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900106import android.view.LayoutInflater;
107import android.view.View;
108import android.view.ViewGroup;
Wale Ogunwale3a931692016-11-02 16:49:48 -0700109import android.view.Window;
Yohei Yukawa6e875592019-01-28 00:49:30 -0800110import android.view.WindowManager.LayoutParams;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700111import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
satokab751aa2010-09-14 19:17:36 +0900112import android.view.inputmethod.EditorInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113import android.view.inputmethod.InputBinding;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800114import android.view.inputmethod.InputConnection;
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700115import android.view.inputmethod.InputConnectionInspector;
Yohei Yukawa432cf602018-10-21 10:41:37 -0700116import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117import android.view.inputmethod.InputMethod;
118import android.view.inputmethod.InputMethodInfo;
119import android.view.inputmethod.InputMethodManager;
satokab751aa2010-09-14 19:17:36 +0900120import android.view.inputmethod.InputMethodSubtype;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900121import android.widget.ArrayAdapter;
satok01038492012-04-09 21:08:27 +0900122import android.widget.CompoundButton;
123import android.widget.CompoundButton.OnCheckedChangeListener;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900124import android.widget.RadioButton;
satok01038492012-04-09 21:08:27 +0900125import android.widget.Switch;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900126import android.widget.TextView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127
Yohei Yukawa0569a182018-08-28 16:09:28 -0700128import com.android.internal.annotations.GuardedBy;
129import com.android.internal.content.PackageMonitor;
130import com.android.internal.inputmethod.IInputContentUriToken;
Yohei Yukawac54c1172018-09-06 11:39:50 -0700131import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
Yohei Yukawaa468d702018-10-21 11:42:34 -0700132import com.android.internal.inputmethod.InputMethodDebug;
Yohei Yukawa35fa6d52018-10-31 11:33:32 -0700133import com.android.internal.inputmethod.StartInputFlags;
Yohei Yukawac6632df2018-10-21 11:47:16 -0700134import com.android.internal.inputmethod.StartInputReason;
Yohei Yukawa499e3f72018-10-21 20:15:11 -0700135import com.android.internal.inputmethod.UnbindReason;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700136import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
137import com.android.internal.notification.SystemNotificationChannels;
138import com.android.internal.os.HandlerCaller;
139import com.android.internal.os.SomeArgs;
140import com.android.internal.os.TransferPipe;
141import com.android.internal.util.DumpUtils;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700142import com.android.internal.util.IndentingPrintWriter;
143import com.android.internal.view.IInputContext;
144import com.android.internal.view.IInputMethod;
145import com.android.internal.view.IInputMethodClient;
146import com.android.internal.view.IInputMethodManager;
147import com.android.internal.view.IInputMethodSession;
148import com.android.internal.view.IInputSessionCallback;
149import com.android.internal.view.InputBindResult;
Yohei Yukawa603f4d02018-09-11 15:04:58 -0700150import com.android.server.EventLogTags;
151import com.android.server.LocalServices;
152import com.android.server.SystemService;
Yohei Yukawae6b6e0e2018-09-12 16:42:48 -0700153import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
154import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700155import com.android.server.statusbar.StatusBarManagerService;
Adrian Roose99bc052017-11-20 17:55:31 +0100156import com.android.server.wm.WindowManagerInternal;
157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158import java.io.FileDescriptor;
159import java.io.IOException;
160import java.io.PrintWriter;
Yohei Yukawafa0e47e2016-04-05 09:55:56 -0700161import java.lang.annotation.Retention;
Yohei Yukawa25e08132016-06-22 16:31:41 -0700162import java.security.InvalidParameterException;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800163import java.text.SimpleDateFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164import java.util.ArrayList;
Yohei Yukawab8d240f2018-12-26 10:03:11 -0800165import java.util.Arrays;
satok688bd472012-02-09 20:09:17 +0900166import java.util.Collections;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800167import java.util.Date;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168import java.util.List;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800169import java.util.Locale;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800170import java.util.WeakHashMap;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800171import java.util.concurrent.atomic.AtomicInteger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172
173/**
174 * This class provides a system service that manages input methods.
175 */
176public class InputMethodManagerService extends IInputMethodManager.Stub
177 implements ServiceConnection, Handler.Callback {
178 static final boolean DEBUG = false;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700179 static final String TAG = "InputMethodManagerService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180
Yohei Yukawa926488d2017-12-11 17:24:55 -0800181 @Retention(SOURCE)
182 @IntDef({ShellCommandResult.SUCCESS, ShellCommandResult.FAILURE})
183 private @interface ShellCommandResult {
184 int SUCCESS = 0;
185 int FAILURE = -1;
186 }
187
Seigo Nonakad4474cb2015-05-04 16:53:24 -0700188 static final int MSG_SHOW_IM_SUBTYPE_PICKER = 1;
189 static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 2;
190 static final int MSG_SHOW_IM_CONFIG = 3;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 static final int MSG_UNBIND_INPUT = 1000;
193 static final int MSG_BIND_INPUT = 1010;
194 static final int MSG_SHOW_SOFT_INPUT = 1020;
195 static final int MSG_HIDE_SOFT_INPUT = 1030;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700196 static final int MSG_HIDE_CURRENT_INPUT_METHOD = 1035;
Yohei Yukawac54c1172018-09-06 11:39:50 -0700197 static final int MSG_INITIALIZE_IME = 1040;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 static final int MSG_CREATE_SESSION = 1050;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 static final int MSG_START_INPUT = 2000;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800201
Yohei Yukawa33e81792015-11-17 21:14:42 -0800202 static final int MSG_UNBIND_CLIENT = 3000;
203 static final int MSG_BIND_CLIENT = 3010;
Dianne Hackborna6e41342012-05-22 16:30:34 -0700204 static final int MSG_SET_ACTIVE = 3020;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700205 static final int MSG_SET_INTERACTIVE = 3030;
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800206 static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -0800207 static final int MSG_REPORT_PRE_RENDERED = 3060;
208 static final int MSG_APPLY_IME_VISIBILITY = 3070;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800209
satok01038492012-04-09 21:08:27 +0900210 static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
211
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -0700212 static final int MSG_SYSTEM_UNLOCK_USER = 5000;
213
Satoshi Kataokabcacc322013-10-21 17:57:27 -0700214 static final long TIME_TO_RECONNECT = 3 * 1000;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800215
satokf9f01002011-05-19 21:31:50 +0900216 static final int SECURE_SUGGESTION_SPANS_MAX_SIZE = 20;
217
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +0900218 private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
satokb6359412011-06-28 17:47:41 +0900219 private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +0900220
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700221 /**
222 * Binding flags for establishing connection to the {@link InputMethodService}.
223 */
224 private static final int IME_CONNECTION_BIND_FLAGS =
225 Context.BIND_AUTO_CREATE
226 | Context.BIND_NOT_VISIBLE
227 | Context.BIND_NOT_FOREGROUND
Yohei Yukawaad78a612017-08-04 01:57:27 -0700228 | Context.BIND_IMPORTANT_BACKGROUND;
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700229
230 /**
231 * Binding flags used only while the {@link InputMethodService} is showing window.
232 */
233 private static final int IME_VISIBLE_BIND_FLAGS =
234 Context.BIND_AUTO_CREATE
235 | Context.BIND_TREAT_LIKE_ACTIVITY
Yohei Yukawaad78a612017-08-04 01:57:27 -0700236 | Context.BIND_FOREGROUND_SERVICE
237 | Context.BIND_SHOWING_UI;
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700238
Yohei Yukawafa0e47e2016-04-05 09:55:56 -0700239 @Retention(SOURCE)
240 @IntDef({HardKeyboardBehavior.WIRELESS_AFFORDANCE, HardKeyboardBehavior.WIRED_AFFORDANCE})
241 private @interface HardKeyboardBehavior {
242 int WIRELESS_AFFORDANCE = 0;
243 int WIRED_AFFORDANCE = 1;
244 }
satok4e4569d2010-11-19 18:45:53 +0900245
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900246 /**
247 * A protected broadcast intent action for internal use for {@link PendingIntent} in
248 * the notification.
249 */
250 private static final String ACTION_SHOW_INPUT_METHOD_PICKER =
Yohei Yukawa603f4d02018-09-11 15:04:58 -0700251 "com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER";
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900252
Tarandeep Singh75a92392018-01-12 14:58:59 -0800253 /**
254 * Debug flag for overriding runtime {@link SystemProperties}.
255 */
256 @AnyThread
257 private static final class DebugFlag {
258 private static final Object LOCK = new Object();
259 private final String mKey;
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700260 private final boolean mDefaultValue;
Tarandeep Singh75a92392018-01-12 14:58:59 -0800261 @GuardedBy("LOCK")
262 private boolean mValue;
263
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700264 public DebugFlag(String key, boolean defaultValue) {
Tarandeep Singh75a92392018-01-12 14:58:59 -0800265 mKey = key;
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700266 mDefaultValue = defaultValue;
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700267 mValue = SystemProperties.getBoolean(key, defaultValue);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800268 }
269
270 void refresh() {
271 synchronized (LOCK) {
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700272 mValue = SystemProperties.getBoolean(mKey, mDefaultValue);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800273 }
274 }
275
276 boolean value() {
277 synchronized (LOCK) {
278 return mValue;
279 }
280 }
281 }
282
283 /**
284 * Debug flags that can be overridden using "adb shell setprop <key>"
285 * Note: These flags are cached. To refresh, run "adb shell ime refresh_debug_properties".
286 */
287 private static final class DebugFlags {
288 static final DebugFlag FLAG_OPTIMIZE_START_INPUT =
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700289 new DebugFlag("debug.optimize_startinput", false);
Tarandeep Singheadb1392018-11-09 18:15:57 +0100290 static final DebugFlag FLAG_PRE_RENDER_IME_VIEWS =
291 new DebugFlag("persist.pre_render_ime_views", false);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800292 }
293
Yohei Yukawaa7babbb2019-01-08 16:45:34 -0800294 @UserIdInt
295 private int mLastSwitchUserId;
Tarandeep Singh75a92392018-01-12 14:58:59 -0800296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 final Context mContext;
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -0800298 final Resources mRes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 final Handler mHandler;
satokd87c2592010-09-29 11:52:06 +0900300 final InputMethodSettings mSettings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 final SettingsObserver mSettingsObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 final IWindowManager mIWindowManager;
Seigo Nonaka7309b122015-08-17 18:34:13 -0700303 final WindowManagerInternal mWindowManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 final HandlerCaller mCaller;
Dianne Hackborn119bbc32013-03-22 17:27:25 -0700305 final boolean mHasFeature;
Yohei Yukawab557d572018-12-29 21:26:26 -0800306 private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
307 new ArrayMap<>();
Tarandeep Singheadb1392018-11-09 18:15:57 +0100308 private final boolean mIsLowRam;
satok01038492012-04-09 21:08:27 +0900309 private final HardKeyboardListener mHardKeyboardListener;
Yohei Yukawae63b5fa2014-09-19 13:14:55 +0900310 private final AppOpsManager mAppOpsManager;
Yohei Yukawaed4952a2016-02-17 07:57:25 -0800311 private final UserManager mUserManager;
Yohei Yukawa42081402019-01-15 09:57:50 -0800312 private final UserManagerInternal mUserManagerInternal;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 // All known input methods. mMethodMap also serves as the global
315 // lock for this class.
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700316 final ArrayList<InputMethodInfo> mMethodList = new ArrayList<>();
Yohei Yukawa1dd7de62018-11-20 19:25:29 -0800317 final ArrayMap<String, InputMethodInfo> mMethodMap = new ArrayMap<>();
satokf9f01002011-05-19 21:31:50 +0900318 private final LruCache<SuggestionSpan, InputMethodInfo> mSecureSuggestionSpans =
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700319 new LruCache<>(SECURE_SUGGESTION_SPANS_MAX_SIZE);
Satoshi Kataokad787f692013-10-26 04:44:21 +0900320 private final InputMethodSubtypeSwitchingController mSwitchingController;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800321
Yohei Yukawae0733062017-02-09 22:49:35 -0800322 /**
323 * Tracks how many times {@link #mMethodMap} was updated.
324 */
325 @GuardedBy("mMethodMap")
326 private int mMethodMapUpdateCount = 0;
327
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -0700328 // Used to bring IME service up to visible adjustment while it is being shown.
329 final ServiceConnection mVisibleConnection = new ServiceConnection() {
Yohei Yukawad3ef8422018-06-07 16:28:07 -0700330 @Override public void onBindingDied(ComponentName name) {
331 synchronized (mMethodMap) {
332 if (mVisibleBound) {
333 mContext.unbindService(mVisibleConnection);
334 mVisibleBound = false;
335 }
336 }
337 }
338
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -0700339 @Override public void onServiceConnected(ComponentName name, IBinder service) {
340 }
341
342 @Override public void onServiceDisconnected(ComponentName name) {
343 }
344 };
345 boolean mVisibleBound = false;
346
satok7cfc0ed2011-06-20 21:29:36 +0900347 // Ongoing notification
Dianne Hackborn661cd522011-08-22 00:26:20 -0700348 private NotificationManager mNotificationManager;
349 private KeyguardManager mKeyguardManager;
Griff Hazen6090c262016-03-25 08:11:24 -0700350 private @Nullable StatusBarManagerService mStatusBar;
Chris Wren1ce4b6d2015-06-11 10:19:43 -0400351 private Notification.Builder mImeSwitcherNotification;
Dianne Hackborn661cd522011-08-22 00:26:20 -0700352 private PendingIntent mImeSwitchPendingIntent;
satokb858c732011-07-22 19:54:34 +0900353 private boolean mShowOngoingImeSwitcherForPhones;
satok7cfc0ed2011-06-20 21:29:36 +0900354 private boolean mNotificationShown;
355
Tadashi G. Takaoka8c6d4772014-08-05 15:29:17 +0900356 static class SessionState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 final ClientState client;
358 final IInputMethod method;
Jeff Brownc28867a2013-03-26 15:42:39 -0700359
360 IInputMethodSession session;
361 InputChannel channel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 @Override
364 public String toString() {
365 return "SessionState{uid " + client.uid + " pid " + client.pid
366 + " method " + Integer.toHexString(
367 System.identityHashCode(method))
368 + " session " + Integer.toHexString(
369 System.identityHashCode(session))
Jeff Brownc28867a2013-03-26 15:42:39 -0700370 + " channel " + channel
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 + "}";
372 }
373
374 SessionState(ClientState _client, IInputMethod _method,
Jeff Brownc28867a2013-03-26 15:42:39 -0700375 IInputMethodSession _session, InputChannel _channel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 client = _client;
377 method = _method;
378 session = _session;
Jeff Brownc28867a2013-03-26 15:42:39 -0700379 channel = _channel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 }
381 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800382
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700383 private static final class ClientDeathRecipient implements IBinder.DeathRecipient {
384 private final InputMethodManagerService mImms;
385 private final IInputMethodClient mClient;
386
387 ClientDeathRecipient(InputMethodManagerService imms, IInputMethodClient client) {
388 mImms = imms;
389 mClient = client;
390 }
391
392 @Override
393 public void binderDied() {
394 mImms.removeClient(mClient);
395 }
396 }
397
Jeff Brownc28867a2013-03-26 15:42:39 -0700398 static final class ClientState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 final IInputMethodClient client;
400 final IInputContext inputContext;
401 final int uid;
402 final int pid;
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800403 final int selfReportedDisplayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 final InputBinding binding;
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700405 final ClientDeathRecipient clientDeathRecipient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 boolean sessionRequested;
Tarandeep Singheadb1392018-11-09 18:15:57 +0100408 // Determines if IMEs should be pre-rendered.
409 // DebugFlag can be flipped anytime. This flag is kept per-client to maintain behavior
410 // through the life of the current client.
411 boolean shouldPreRenderIme;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 SessionState curSession;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 @Override
415 public String toString() {
416 return "ClientState{" + Integer.toHexString(
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800417 System.identityHashCode(this)) + " uid=" + uid
418 + " pid=" + pid + " displayId=" + selfReportedDisplayId + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 }
420
421 ClientState(IInputMethodClient _client, IInputContext _inputContext,
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800422 int _uid, int _pid, int _selfReportedDisplayId,
423 ClientDeathRecipient _clientDeathRecipient) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 client = _client;
425 inputContext = _inputContext;
426 uid = _uid;
427 pid = _pid;
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800428 selfReportedDisplayId = _selfReportedDisplayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700430 clientDeathRecipient = _clientDeathRecipient;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 }
432 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800433
Yohei Yukawaac9311e2018-11-20 19:25:23 -0800434 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 /**
Dianne Hackborna34f1ad2009-09-02 13:26:28 -0700437 * Set once the system is ready to run third party code.
438 */
439 boolean mSystemReady;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800440
Dianne Hackborna34f1ad2009-09-02 13:26:28 -0700441 /**
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700442 * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method.
443 * method. This is to be synchronized with the secure settings keyed with
444 * {@link Settings.Secure#DEFAULT_INPUT_METHOD}.
445 *
446 * <p>This can be transiently {@code null} when the system is re-initializing input method
447 * settings, e.g., the system locale is just changed.</p>
448 *
449 * <p>Note that {@link #mCurId} is used to track which IME is being connected to
450 * {@link InputMethodManagerService}.</p>
451 *
452 * @see #mCurId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 */
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700454 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 String mCurMethodId;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 /**
458 * The current binding sequence number, incremented every time there is
459 * a new bind performed.
460 */
461 int mCurSeq;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 /**
464 * The client that is currently bound to an input method.
465 */
466 ClientState mCurClient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 /**
Yohei Yukawae39d4ed2015-11-19 03:38:49 -0800469 * The last window token that we confirmed to be focused. This is always updated upon reports
470 * from the input method client. If the window state is already changed before the report is
471 * handled, this field just keeps the last value.
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700472 */
473 IBinder mCurFocusedWindow;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800474
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700475 /**
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -0700476 * The last window token that we confirmed that IME started talking to. This is always updated
477 * upon reports from the input method. If the window state is already changed before the report
478 * is handled, this field just keeps the last value.
479 */
480 IBinder mLastImeTargetWindow;
481
482 /**
Yohei Yukawa6e875592019-01-28 00:49:30 -0800483 * {@link LayoutParams#softInputMode} of {@link #mCurFocusedWindow}.
Yohei Yukawa22a89232017-02-12 16:38:59 -0800484 *
485 * @see #mCurFocusedWindow
486 */
Yohei Yukawab0c26452018-10-21 10:42:52 -0700487 @SoftInputModeFlags
Yohei Yukawa22a89232017-02-12 16:38:59 -0800488 int mCurFocusedWindowSoftInputMode;
489
490 /**
Tarandeep Singheb570612018-01-29 16:20:32 -0800491 * The client by which {@link #mCurFocusedWindow} was reported.
Yohei Yukawae39d4ed2015-11-19 03:38:49 -0800492 */
493 ClientState mCurFocusedWindowClient;
494
495 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 * The input context last provided by the current client.
497 */
498 IInputContext mCurInputContext;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 /**
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700501 * The missing method flags for the input context last provided by the current client.
502 *
503 * @see android.view.inputmethod.InputConnectionInspector.MissingMethodFlags
504 */
Yohei Yukawa432cf602018-10-21 10:41:37 -0700505 @MissingMethodFlags
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700506 int mCurInputContextMissingMethods;
507
508 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 * The attributes last provided by the current client.
510 */
511 EditorInfo mCurAttribute;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800512
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 /**
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700514 * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 * connected to or in the process of connecting to.
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700516 *
517 * <p>This can be {@code null} when no input method is connected.</p>
518 *
519 * @see #mCurMethodId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 */
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700521 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 String mCurId;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800523
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 /**
satokab751aa2010-09-14 19:17:36 +0900525 * The current subtype of the current input method.
526 */
527 private InputMethodSubtype mCurrentSubtype;
528
John Spurlocke0980502013-10-25 11:59:29 -0400529 // Was the keyguard locked when this client became current?
530 private boolean mCurClientInKeyguard;
531
satokab751aa2010-09-14 19:17:36 +0900532 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 * Set to true if our ServiceConnection is currently actively bound to
534 * a service (whether or not we have gotten its IBinder back yet).
535 */
536 boolean mHaveConnection;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800537
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538 /**
539 * Set if the client has asked for the input method to be shown.
540 */
541 boolean mShowRequested;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 /**
544 * Set if we were explicitly told to show the input method.
545 */
546 boolean mShowExplicitlyRequested;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800547
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 /**
549 * Set if we were forced to be shown.
550 */
551 boolean mShowForced;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 /**
554 * Set if we last told the input method to show itself.
555 */
556 boolean mInputShown;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 /**
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800559 * {@code true} if the current input method is in fullscreen mode.
560 */
561 boolean mInFullscreenMode;
562
563 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 * The Intent used to connect to the current input method.
565 */
566 Intent mCurIntent;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 /**
569 * The token we have made for the currently active input method, to
570 * identify it in the future.
571 */
572 IBinder mCurToken;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 /**
lumark90120a82018-08-15 00:33:03 +0800575 * The displayId of current active input method.
576 */
577 int mCurTokenDisplayId = INVALID_DISPLAY;
578
lumarkef1965b2018-09-12 17:42:53 +0800579 final ImeDisplayValidator mImeDisplayValidator;
580
lumark90120a82018-08-15 00:33:03 +0800581 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 * If non-null, this is the input method service we are currently connected
583 * to.
584 */
585 IInputMethod mCurMethod;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800586
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 /**
588 * Time that we last initiated a bind to the input method, to determine
589 * if we should try to disconnect and reconnect to it.
590 */
591 long mLastBindTime;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800592
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 /**
594 * Have we called mCurMethod.bindInput()?
595 */
596 boolean mBoundToMethod;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 /**
599 * Currently enabled session. Only touched by service thread, not
600 * protected by a lock.
601 */
602 SessionState mEnabledSession;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 /**
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700605 * True if the device is currently interactive with user. The value is true initially.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 */
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700607 boolean mIsInteractive = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800608
Joe Onorato857fd9b2011-01-27 15:08:35 -0800609 int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900610
611 /**
612 * A set of status bits regarding the active IME.
613 *
614 * <p>This value is a combination of following two bits:</p>
615 * <dl>
616 * <dt>{@link InputMethodService#IME_ACTIVE}</dt>
617 * <dd>
618 * If this bit is ON, connected IME is ready to accept touch/key events.
619 * </dd>
620 * <dt>{@link InputMethodService#IME_VISIBLE}</dt>
621 * <dd>
622 * If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
623 * </dd>
Tarandeep Singheadb1392018-11-09 18:15:57 +0100624 * dt>{@link InputMethodService#IME_INVISIBLE}</dt>
625 * <dd> If this bit is ON, IME is ready with views from last EditorInfo but is
626 * currently invisible.
627 * </dd>
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900628 * </dl>
629 * <em>Do not update this value outside of setImeWindowStatus.</em>
630 */
Joe Onorato857fd9b2011-01-27 15:08:35 -0800631 int mImeWindowVis;
632
Ken Wakasa05dbb652011-08-22 15:22:43 +0900633 private AlertDialog.Builder mDialogBuilder;
634 private AlertDialog mSwitchingDialog;
Wale Ogunwale3a931692016-11-02 16:49:48 -0700635 private IBinder mSwitchingDialogToken = new Binder();
satok01038492012-04-09 21:08:27 +0900636 private View mSwitchingDialogTitleView;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900637 private InputMethodInfo[] mIms;
638 private int[] mSubtypeIds;
Yohei Yukawae985c242016-02-24 18:27:04 -0800639 private LocaleList mLastSystemLocales;
Michael Wright7b5a96b2014-08-09 19:28:42 -0700640 private boolean mShowImeWithHardKeyboard;
Anna Galusza9b278112016-01-04 11:37:37 -0800641 private boolean mAccessibilityRequestingNoSoftKeyboard;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +0900642 private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
643 private final IPackageManager mIPackageManager;
Jason Monk3e189872016-01-12 09:10:34 -0500644 private final String mSlotIme;
Yohei Yukawafa0e47e2016-04-05 09:55:56 -0700645 @HardKeyboardBehavior
646 private final int mHardKeyboardBehavior;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800647
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800648 /**
649 * Internal state snapshot when {@link #MSG_START_INPUT} message is about to be posted to the
650 * internal message queue. Any subsequent state change inside {@link InputMethodManagerService}
651 * will not affect those tasks that are already posted.
652 *
653 * <p>Posting {@link #MSG_START_INPUT} message basically means that
654 * {@link InputMethodService#doStartInput(InputConnection, EditorInfo, boolean)} will be called
655 * back in the current IME process shortly, which will also affect what the current IME starts
656 * receiving from {@link InputMethodService#getCurrentInputConnection()}. In other words, this
657 * snapshot will be taken every time when {@link InputMethodManagerService} is initiating a new
658 * logical input session between the client application and the current IME.</p>
659 *
660 * <p>Be careful to not keep strong references to this object forever, which can prevent
661 * {@link StartInputInfo#mImeToken} and {@link StartInputInfo#mTargetWindow} from being GC-ed.
662 * </p>
663 */
664 private static class StartInputInfo {
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800665 private static final AtomicInteger sSequenceNumber = new AtomicInteger(0);
666
667 final int mSequenceNumber;
668 final long mTimestamp;
669 final long mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800670 @UserIdInt
671 final int mImeUserId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800672 @NonNull
673 final IBinder mImeToken;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800674 final int mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800675 @NonNull
676 final String mImeId;
Yohei Yukawadc66e522018-10-21 10:43:14 -0700677 @StartInputReason
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800678 final int mStartInputReason;
679 final boolean mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800680 @UserIdInt
681 final int mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800682 final int mTargetDisplayId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800683 @Nullable
684 final IBinder mTargetWindow;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800685 @NonNull
686 final EditorInfo mEditorInfo;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700687 @SoftInputModeFlags
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800688 final int mTargetWindowSoftInputMode;
689 final int mClientBindSequenceNumber;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800690
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800691 StartInputInfo(@UserIdInt int imeUserId, @NonNull IBinder imeToken, int imeDisplayId,
692 @NonNull String imeId, @StartInputReason int startInputReason, boolean restarting,
693 @UserIdInt int targetUserId, int targetDisplayId, @Nullable IBinder targetWindow,
694 @NonNull EditorInfo editorInfo, @SoftInputModeFlags int targetWindowSoftInputMode,
695 int clientBindSequenceNumber) {
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800696 mSequenceNumber = sSequenceNumber.getAndIncrement();
697 mTimestamp = SystemClock.uptimeMillis();
698 mWallTime = System.currentTimeMillis();
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800699 mImeUserId = imeUserId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800700 mImeToken = imeToken;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800701 mImeDisplayId = imeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800702 mImeId = imeId;
703 mStartInputReason = startInputReason;
704 mRestarting = restarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800705 mTargetUserId = targetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800706 mTargetDisplayId = targetDisplayId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800707 mTargetWindow = targetWindow;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800708 mEditorInfo = editorInfo;
709 mTargetWindowSoftInputMode = targetWindowSoftInputMode;
710 mClientBindSequenceNumber = clientBindSequenceNumber;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800711 }
712 }
713
Yohei Yukawab37d8bd2017-02-13 18:29:05 -0800714 @GuardedBy("mMethodMap")
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -0700715 private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800716
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800717 /**
718 * A ring buffer to store the history of {@link StartInputInfo}.
719 */
720 private static final class StartInputHistory {
721 /**
722 * Entry size for non low-RAM devices.
723 *
724 * <p>TODO: Consider to follow what other system services have been doing to manage
725 * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
726 */
727 private final static int ENTRY_SIZE_FOR_HIGH_RAM_DEVICE = 16;
728
729 /**
730 * Entry size for non low-RAM devices.
731 *
732 * <p>TODO: Consider to follow what other system services have been doing to manage
733 * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
734 */
735 private final static int ENTRY_SIZE_FOR_LOW_RAM_DEVICE = 5;
736
737 private static int getEntrySize() {
738 if (ActivityManager.isLowRamDeviceStatic()) {
739 return ENTRY_SIZE_FOR_LOW_RAM_DEVICE;
740 } else {
741 return ENTRY_SIZE_FOR_HIGH_RAM_DEVICE;
742 }
743 }
744
745 /**
746 * Backing store for the ring bugger.
747 */
748 private final Entry[] mEntries = new Entry[getEntrySize()];
749
750 /**
751 * An index of {@link #mEntries}, to which next {@link #addEntry(StartInputInfo)} should
752 * write.
753 */
754 private int mNextIndex = 0;
755
756 /**
757 * Recyclable entry to store the information in {@link StartInputInfo}.
758 */
759 private static final class Entry {
760 int mSequenceNumber;
761 long mTimestamp;
762 long mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800763 @UserIdInt
764 int mImeUserId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800765 @NonNull
766 String mImeTokenString;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800767 int mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800768 @NonNull
769 String mImeId;
Yohei Yukawadc66e522018-10-21 10:43:14 -0700770 @StartInputReason
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800771 int mStartInputReason;
772 boolean mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800773 @UserIdInt
774 int mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800775 int mTargetDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800776 @NonNull
777 String mTargetWindowString;
778 @NonNull
779 EditorInfo mEditorInfo;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700780 @SoftInputModeFlags
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800781 int mTargetWindowSoftInputMode;
782 int mClientBindSequenceNumber;
783
784 Entry(@NonNull StartInputInfo original) {
785 set(original);
786 }
787
788 void set(@NonNull StartInputInfo original) {
789 mSequenceNumber = original.mSequenceNumber;
790 mTimestamp = original.mTimestamp;
791 mWallTime = original.mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800792 mImeUserId = original.mImeUserId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800793 // Intentionally convert to String so as not to keep a strong reference to a Binder
794 // object.
795 mImeTokenString = String.valueOf(original.mImeToken);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800796 mImeDisplayId = original.mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800797 mImeId = original.mImeId;
798 mStartInputReason = original.mStartInputReason;
799 mRestarting = original.mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800800 mTargetUserId = original.mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800801 mTargetDisplayId = original.mTargetDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800802 // Intentionally convert to String so as not to keep a strong reference to a Binder
803 // object.
804 mTargetWindowString = String.valueOf(original.mTargetWindow);
805 mEditorInfo = original.mEditorInfo;
806 mTargetWindowSoftInputMode = original.mTargetWindowSoftInputMode;
807 mClientBindSequenceNumber = original.mClientBindSequenceNumber;
808 }
809 }
810
811 /**
812 * Add a new entry and discard the oldest entry as needed.
813 * @param info {@lin StartInputInfo} to be added.
814 */
815 void addEntry(@NonNull StartInputInfo info) {
816 final int index = mNextIndex;
817 if (mEntries[index] == null) {
818 mEntries[index] = new Entry(info);
819 } else {
820 mEntries[index].set(info);
821 }
822 mNextIndex = (mNextIndex + 1) % mEntries.length;
823 }
824
825 void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
826 final SimpleDateFormat dataFormat =
827 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
828
829 for (int i = 0; i < mEntries.length; ++i) {
830 final Entry entry = mEntries[(i + mNextIndex) % mEntries.length];
831 if (entry == null) {
832 continue;
833 }
834 pw.print(prefix);
835 pw.println("StartInput #" + entry.mSequenceNumber + ":");
836
837 pw.print(prefix);
838 pw.println(" time=" + dataFormat.format(new Date(entry.mWallTime))
839 + " (timestamp=" + entry.mTimestamp + ")"
840 + " reason="
Yohei Yukawaa468d702018-10-21 11:42:34 -0700841 + InputMethodDebug.startInputReasonToString(entry.mStartInputReason)
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800842 + " restarting=" + entry.mRestarting);
843
844 pw.print(prefix);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800845 pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]");
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800846 pw.print(" imeUserId=" + entry.mImeUserId);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800847 pw.println(" imeDisplayId=" + entry.mImeDisplayId);
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800848
849 pw.print(prefix);
850 pw.println(" targetWin=" + entry.mTargetWindowString
851 + " [" + entry.mEditorInfo.packageName + "]"
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800852 + " targetUserId=" + entry.mTargetUserId
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800853 + " targetDisplayId=" + entry.mTargetDisplayId
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800854 + " clientBindSeq=" + entry.mClientBindSequenceNumber);
855
856 pw.print(prefix);
Yohei Yukawaa468d702018-10-21 11:42:34 -0700857 pw.println(" softInputMode=" + InputMethodDebug.softInputModeToString(
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800858 entry.mTargetWindowSoftInputMode));
859
860 pw.print(prefix);
861 pw.println(" inputType=0x" + Integer.toHexString(entry.mEditorInfo.inputType)
862 + " imeOptions=0x" + Integer.toHexString(entry.mEditorInfo.imeOptions)
863 + " fieldId=0x" + Integer.toHexString(entry.mEditorInfo.fieldId)
864 + " fieldName=" + entry.mEditorInfo.fieldName
865 + " actionId=" + entry.mEditorInfo.actionId
866 + " actionLabel=" + entry.mEditorInfo.actionLabel);
867 }
868 }
869 }
870
871 @GuardedBy("mMethodMap")
872 @NonNull
873 private final StartInputHistory mStartInputHistory = new StartInputHistory();
874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 class SettingsObserver extends ContentObserver {
Yohei Yukawa81482972015-06-04 00:58:59 -0700876 int mUserId;
877 boolean mRegistered = false;
Yohei Yukawa7b574cb2016-03-16 17:22:22 -0700878 @NonNull
Dianne Hackbornfd7aded2013-01-22 17:10:23 -0800879 String mLastEnabled = "";
880
Yohei Yukawa81482972015-06-04 00:58:59 -0700881 /**
882 * <em>This constructor must be called within the lock.</em>
883 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 SettingsObserver(Handler handler) {
885 super(handler);
Yohei Yukawa81482972015-06-04 00:58:59 -0700886 }
887
Yohei Yukawa7b18aec2016-03-07 13:04:32 -0800888 public void registerContentObserverLocked(@UserIdInt int userId) {
Yohei Yukawa81482972015-06-04 00:58:59 -0700889 if (mRegistered && mUserId == userId) {
890 return;
891 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 ContentResolver resolver = mContext.getContentResolver();
Yohei Yukawa81482972015-06-04 00:58:59 -0700893 if (mRegistered) {
894 mContext.getContentResolver().unregisterContentObserver(this);
895 mRegistered = false;
896 }
897 if (mUserId != userId) {
898 mLastEnabled = "";
899 mUserId = userId;
900 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700902 Settings.Secure.DEFAULT_INPUT_METHOD), false, this, userId);
satokab751aa2010-09-14 19:17:36 +0900903 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700904 Settings.Secure.ENABLED_INPUT_METHODS), false, this, userId);
satokb6109bb2011-02-03 22:24:54 +0900905 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700906 Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, userId);
Michael Wright7b5a96b2014-08-09 19:28:42 -0700907 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700908 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
Anna Galusza9b278112016-01-04 11:37:37 -0800909 resolver.registerContentObserver(Settings.Secure.getUriFor(
910 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, userId);
Yohei Yukawa81482972015-06-04 00:58:59 -0700911 mRegistered = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800913
Michael Wright7b5a96b2014-08-09 19:28:42 -0700914 @Override public void onChange(boolean selfChange, Uri uri) {
Anna Galusza9b278112016-01-04 11:37:37 -0800915 final Uri showImeUri = Settings.Secure.getUriFor(
916 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
917 final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
918 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919 synchronized (mMethodMap) {
Michael Wright7b5a96b2014-08-09 19:28:42 -0700920 if (showImeUri.equals(uri)) {
921 updateKeyboardFromSettingsLocked();
Anna Galusza9b278112016-01-04 11:37:37 -0800922 } else if (accessibilityRequestingNoImeUri.equals(uri)) {
Phil Weaver03a65b02018-07-19 16:07:57 -0700923 final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
Anna Galusza9b278112016-01-04 11:37:37 -0800924 mContext.getContentResolver(),
Phil Weaver03a65b02018-07-19 16:07:57 -0700925 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, mUserId);
926 mAccessibilityRequestingNoSoftKeyboard =
927 (accessibilitySoftKeyboardSetting & AccessibilityService.SHOW_MODE_MASK)
928 == AccessibilityService.SHOW_MODE_HIDDEN;
Anna Galusza9b278112016-01-04 11:37:37 -0800929 if (mAccessibilityRequestingNoSoftKeyboard) {
930 final boolean showRequested = mShowRequested;
931 hideCurrentInputLocked(0, null);
932 mShowRequested = showRequested;
933 } else if (mShowRequested) {
934 showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
935 }
Michael Wright7b5a96b2014-08-09 19:28:42 -0700936 } else {
937 boolean enabledChanged = false;
938 String newEnabled = mSettings.getEnabledInputMethodsStr();
939 if (!mLastEnabled.equals(newEnabled)) {
940 mLastEnabled = newEnabled;
941 enabledChanged = true;
942 }
943 updateInputMethodsFromSettingsLocked(enabledChanged);
Dianne Hackbornfd7aded2013-01-22 17:10:23 -0800944 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 }
946 }
Yohei Yukawa81482972015-06-04 00:58:59 -0700947
948 @Override
949 public String toString() {
950 return "SettingsObserver{mUserId=" + mUserId + " mRegistered=" + mRegistered
951 + " mLastEnabled=" + mLastEnabled + "}";
952 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800954
Yohei Yukawa79247822017-01-23 15:26:15 -0800955 class ImmsBroadcastReceiver extends BroadcastReceiver {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +0900956 @Override
957 public void onReceive(Context context, Intent intent) {
958 final String action = intent.getAction();
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700959 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +0900960 hideInputMethodMenu();
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700961 // No need to update mIsInteractive
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +0900962 return;
Amith Yamasani734983f2014-03-04 16:48:05 -0800963 } else if (Intent.ACTION_USER_ADDED.equals(action)
964 || Intent.ACTION_USER_REMOVED.equals(action)) {
Kenny Guy2a764942014-04-02 13:29:20 +0100965 updateCurrentProfileIds();
Amith Yamasani734983f2014-03-04 16:48:05 -0800966 return;
Yohei Yukawa79247822017-01-23 15:26:15 -0800967 } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
Yohei Yukawa0d7aff82017-02-10 00:40:51 -0800968 onActionLocaleChanged();
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900969 } else if (ACTION_SHOW_INPUT_METHOD_PICKER.equals(action)) {
970 // ACTION_SHOW_INPUT_METHOD_PICKER action is a protected-broadcast and it is
971 // guaranteed to be send only from the system, so that there is no need for extra
972 // security check such as
973 // {@link #canShowInputMethodPickerLocked(IInputMethodClient)}.
974 mHandler.obtainMessage(
975 MSG_SHOW_IM_SUBTYPE_PICKER,
lumark0b05f9e2018-11-26 15:09:06 +0800976 // TODO(b/120076400): Design and implement IME switcher for heterogeneous
977 // navbar configuration.
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900978 InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES,
lumark0b05f9e2018-11-26 15:09:06 +0800979 DEFAULT_DISPLAY).sendToTarget();
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +0900980 } else {
981 Slog.w(TAG, "Unexpected intent " + intent);
982 }
983 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800985
Yohei Yukawa0d7aff82017-02-10 00:40:51 -0800986 /**
987 * Handles {@link Intent#ACTION_LOCALE_CHANGED}.
988 *
989 * <p>Note: For historical reasons, {@link Intent#ACTION_LOCALE_CHANGED} has been sent to all
990 * the users. We should ignore this event if this is about any background user's locale.</p>
991 *
992 * <p>Caution: This method must not be called when system is not ready.</p>
993 */
994 void onActionLocaleChanged() {
995 synchronized (mMethodMap) {
996 final LocaleList possibleNewLocale = mRes.getConfiguration().getLocales();
997 if (possibleNewLocale != null && possibleNewLocale.equals(mLastSystemLocales)) {
998 return;
999 }
1000 buildInputMethodListLocked(true);
1001 // If the locale is changed, needs to reset the default ime
1002 resetDefaultImeLocked(mContext);
1003 updateFromSettingsLocked(true);
1004 mLastSystemLocales = possibleNewLocale;
1005 }
1006 }
1007
Yohei Yukawac4e44912017-02-09 19:30:22 -08001008 final class MyPackageMonitor extends PackageMonitor {
1009 /**
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001010 * Package names that are known to contain {@link InputMethodService}.
Yohei Yukawac4e44912017-02-09 19:30:22 -08001011 *
1012 * <p>No need to include packages because of direct-boot unaware IMEs since we always rescan
1013 * all the packages when the user is unlocked, and direct-boot awareness will not be changed
1014 * dynamically unless the entire package is updated, which also always triggers package
1015 * rescanning.</p>
1016 */
1017 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001018 final private ArraySet<String> mKnownImePackageNames = new ArraySet<>();
1019
1020 /**
1021 * Packages that are appeared, disappeared, or modified for whatever reason.
1022 *
1023 * <p>Note: For now we intentionally use {@link ArrayList} instead of {@link ArraySet}
1024 * because 1) the number of elements is almost always 1 or so, and 2) we do not care
1025 * duplicate elements for our use case.</p>
1026 *
1027 * <p>This object must be accessed only from callback methods in {@link PackageMonitor},
1028 * which should be bound to {@link #getRegisteredHandler()}.</p>
1029 */
1030 private final ArrayList<String> mChangedPackages = new ArrayList<>();
1031
1032 /**
1033 * {@code true} if one or more packages that contain {@link InputMethodService} appeared.
1034 *
1035 * <p>This field must be accessed only from callback methods in {@link PackageMonitor},
1036 * which should be bound to {@link #getRegisteredHandler()}.</p>
1037 */
1038 private boolean mImePackageAppeared = false;
Yohei Yukawac4e44912017-02-09 19:30:22 -08001039
1040 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001041 void clearKnownImePackageNamesLocked() {
1042 mKnownImePackageNames.clear();
Yohei Yukawac4e44912017-02-09 19:30:22 -08001043 }
1044
1045 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001046 final void addKnownImePackageNameLocked(@NonNull String packageName) {
1047 mKnownImePackageNames.add(packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08001048 }
1049
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001050 @GuardedBy("mMethodMap")
1051 private boolean isChangingPackagesOfCurrentUserLocked() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001052 final int userId = getChangingUserId();
1053 final boolean retval = userId == mSettings.getCurrentUserId();
1054 if (DEBUG) {
satok81f8b7c2012-12-04 20:42:56 +09001055 if (!retval) {
1056 Slog.d(TAG, "--- ignore this call back from a background user: " + userId);
1057 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001058 }
1059 return retval;
1060 }
1061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001063 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 synchronized (mMethodMap) {
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001065 if (!isChangingPackagesOfCurrentUserLocked()) {
1066 return false;
1067 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001068 String curInputMethodId = mSettings.getSelectedInputMethod();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 final int N = mMethodList.size();
1070 if (curInputMethodId != null) {
1071 for (int i=0; i<N; i++) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001072 InputMethodInfo imi = mMethodList.get(i);
1073 if (imi.getId().equals(curInputMethodId)) {
1074 for (String pkg : packages) {
1075 if (imi.getPackageName().equals(pkg)) {
1076 if (!doit) {
1077 return true;
1078 }
satok723a27e2010-11-11 14:58:11 +09001079 resetSelectedInputMethodAndSubtypeLocked("");
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001080 chooseNewDefaultIMELocked();
1081 return true;
1082 }
1083 }
1084 }
1085 }
1086 }
1087 }
1088 return false;
1089 }
1090
1091 @Override
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001092 public void onBeginPackageChanges() {
1093 clearPackageChangeState();
1094 }
1095
1096 @Override
1097 public void onPackageAppeared(String packageName, int reason) {
1098 if (!mImePackageAppeared) {
1099 final PackageManager pm = mContext.getPackageManager();
1100 final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
1101 new Intent(InputMethod.SERVICE_INTERFACE).setPackage(packageName),
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08001102 PackageManager.MATCH_DISABLED_COMPONENTS, getChangingUserId());
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001103 // No need to lock this because we access it only on getRegisteredHandler().
1104 if (!services.isEmpty()) {
1105 mImePackageAppeared = true;
1106 }
1107 }
1108 // No need to lock this because we access it only on getRegisteredHandler().
1109 mChangedPackages.add(packageName);
1110 }
1111
1112 @Override
1113 public void onPackageDisappeared(String packageName, int reason) {
1114 // No need to lock this because we access it only on getRegisteredHandler().
1115 mChangedPackages.add(packageName);
1116 }
1117
1118 @Override
1119 public void onPackageModified(String packageName) {
1120 // No need to lock this because we access it only on getRegisteredHandler().
1121 mChangedPackages.add(packageName);
1122 }
1123
1124 @Override
1125 public void onPackagesSuspended(String[] packages) {
1126 // No need to lock this because we access it only on getRegisteredHandler().
1127 for (String packageName : packages) {
1128 mChangedPackages.add(packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08001129 }
1130 }
1131
1132 @Override
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001133 public void onPackagesUnsuspended(String[] packages) {
1134 // No need to lock this because we access it only on getRegisteredHandler().
1135 for (String packageName : packages) {
1136 mChangedPackages.add(packageName);
1137 }
1138 }
1139
1140 @Override
1141 public void onFinishPackageChanges() {
1142 onFinishPackageChangesInternal();
1143 clearPackageChangeState();
1144 }
1145
1146 private void clearPackageChangeState() {
1147 // No need to lock them because we access these fields only on getRegisteredHandler().
1148 mChangedPackages.clear();
1149 mImePackageAppeared = false;
1150 }
1151
Andreas Gampea36dc622018-02-05 17:19:22 -08001152 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001153 private boolean shouldRebuildInputMethodListLocked() {
1154 // This method is guaranteed to be called only by getRegisteredHandler().
1155
1156 // If there is any new package that contains at least one IME, then rebuilt the list
1157 // of IMEs.
1158 if (mImePackageAppeared) {
1159 return true;
1160 }
1161
1162 // Otherwise, check if mKnownImePackageNames and mChangedPackages have any intersection.
1163 // TODO: Consider to create a utility method to do the following test. List.retainAll()
1164 // is an option, but it may still do some extra operations that we do not need here.
1165 final int N = mChangedPackages.size();
1166 for (int i = 0; i < N; ++i) {
1167 final String packageName = mChangedPackages.get(i);
1168 if (mKnownImePackageNames.contains(packageName)) {
1169 return true;
1170 }
1171 }
1172 return false;
1173 }
1174
1175 private void onFinishPackageChangesInternal() {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001176 synchronized (mMethodMap) {
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001177 if (!isChangingPackagesOfCurrentUserLocked()) {
1178 return;
1179 }
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001180 if (!shouldRebuildInputMethodListLocked()) {
1181 return;
1182 }
1183
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001184 InputMethodInfo curIm = null;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001185 String curInputMethodId = mSettings.getSelectedInputMethod();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001186 final int N = mMethodList.size();
1187 if (curInputMethodId != null) {
1188 for (int i=0; i<N; i++) {
1189 InputMethodInfo imi = mMethodList.get(i);
satoke7c6998e2011-06-03 17:57:59 +09001190 final String imiId = imi.getId();
1191 if (imiId.equals(curInputMethodId)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001192 curIm = imi;
1193 }
satoke7c6998e2011-06-03 17:57:59 +09001194
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001195 int change = isPackageDisappearing(imi.getPackageName());
satoke7c6998e2011-06-03 17:57:59 +09001196 if (isPackageModified(imi.getPackageName())) {
Yohei Yukawab557d572018-12-29 21:26:26 -08001197 mAdditionalSubtypeMap.remove(imi.getId());
1198 AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
1199 mSettings.getCurrentUserId());
satoke7c6998e2011-06-03 17:57:59 +09001200 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001201 if (change == PACKAGE_TEMPORARY_CHANGE
1202 || change == PACKAGE_PERMANENT_CHANGE) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001203 Slog.i(TAG, "Input method uninstalled, disabling: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001204 + imi.getComponent());
1205 setInputMethodEnabledLocked(imi.getId(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 }
1207 }
1208 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001209
Yohei Yukawa94e33302016-02-12 19:37:03 -08001210 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 boolean changed = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001213
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001214 if (curIm != null) {
Anna Galusza9b278112016-01-04 11:37:37 -08001215 int change = isPackageDisappearing(curIm.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001216 if (change == PACKAGE_TEMPORARY_CHANGE
1217 || change == PACKAGE_PERMANENT_CHANGE) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001218 ServiceInfo si = null;
1219 try {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001220 si = mIPackageManager.getServiceInfo(
1221 curIm.getComponent(), 0, mSettings.getCurrentUserId());
1222 } catch (RemoteException ex) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001223 }
1224 if (si == null) {
1225 // Uh oh, current input method is no longer around!
1226 // Pick another one...
Joe Onorato8a9b2202010-02-26 18:56:32 -08001227 Slog.i(TAG, "Current input method removed: " + curInputMethodId);
Yohei Yukawa849443c2019-01-21 09:02:25 -08001228 updateSystemUiLocked(0 /* vis */, mBackDisposition);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001229 if (!chooseNewDefaultIMELocked()) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001230 changed = true;
1231 curIm = null;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001232 Slog.i(TAG, "Unsetting current input method");
satok723a27e2010-11-11 14:58:11 +09001233 resetSelectedInputMethodAndSubtypeLocked("");
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001234 }
1235 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001236 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001237 }
satokab751aa2010-09-14 19:17:36 +09001238
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001239 if (curIm == null) {
1240 // We currently don't have a default input method... is
1241 // one now available?
1242 changed = chooseNewDefaultIMELocked();
Yohei Yukawa54d512c2015-05-19 22:15:02 -07001243 } else if (!changed && isPackageModified(curIm.getPackageName())) {
1244 // Even if the current input method is still available, mCurrentSubtype could
1245 // be obsolete when the package is modified in practice.
1246 changed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001247 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001248
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001249 if (changed) {
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08001250 updateFromSettingsLocked(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251 }
1252 }
1253 }
1254 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001255
Jeff Brownc28867a2013-03-26 15:42:39 -07001256 private static final class MethodCallback extends IInputSessionCallback.Stub {
Jean Chalarde0d32a62011-10-20 20:36:07 +09001257 private final InputMethodManagerService mParentIMMS;
Jeff Brownc28867a2013-03-26 15:42:39 -07001258 private final IInputMethod mMethod;
1259 private final InputChannel mChannel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001260
Jeff Brownc28867a2013-03-26 15:42:39 -07001261 MethodCallback(InputMethodManagerService imms, IInputMethod method,
1262 InputChannel channel) {
Jean Chalarde0d32a62011-10-20 20:36:07 +09001263 mParentIMMS = imms;
Jeff Brownc28867a2013-03-26 15:42:39 -07001264 mMethod = method;
1265 mChannel = channel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001267
satoke7c6998e2011-06-03 17:57:59 +09001268 @Override
Jeff Brownc28867a2013-03-26 15:42:39 -07001269 public void sessionCreated(IInputMethodSession session) {
Dianne Hackborn6b6b3fd2014-03-24 11:27:18 -07001270 long ident = Binder.clearCallingIdentity();
1271 try {
1272 mParentIMMS.onSessionCreated(mMethod, session, mChannel);
1273 } finally {
1274 Binder.restoreCallingIdentity(ident);
1275 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 }
1277 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001278
satok01038492012-04-09 21:08:27 +09001279 private class HardKeyboardListener
Seigo Nonaka7309b122015-08-17 18:34:13 -07001280 implements WindowManagerInternal.OnHardKeyboardStatusChangeListener {
satok01038492012-04-09 21:08:27 +09001281 @Override
Michael Wright7b5a96b2014-08-09 19:28:42 -07001282 public void onHardKeyboardStatusChange(boolean available) {
1283 mHandler.sendMessage(mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED,
1284 available ? 1 : 0));
satok01038492012-04-09 21:08:27 +09001285 }
1286
Michael Wright7b5a96b2014-08-09 19:28:42 -07001287 public void handleHardKeyboardStatusChange(boolean available) {
satok01038492012-04-09 21:08:27 +09001288 if (DEBUG) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07001289 Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
satok01038492012-04-09 21:08:27 +09001290 }
1291 synchronized(mMethodMap) {
1292 if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
1293 && mSwitchingDialog.isShowing()) {
1294 mSwitchingDialogTitleView.findViewById(
1295 com.android.internal.R.id.hard_keyboard_section).setVisibility(
1296 available ? View.VISIBLE : View.GONE);
1297 }
1298 }
1299 }
1300 }
1301
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001302 public static final class Lifecycle extends SystemService {
1303 private InputMethodManagerService mService;
1304
1305 public Lifecycle(Context context) {
1306 super(context);
1307 mService = new InputMethodManagerService(context);
1308 }
1309
1310 @Override
1311 public void onStart() {
1312 LocalServices.addService(InputMethodManagerInternal.class,
Yohei Yukawafffc0e52018-09-04 13:24:00 -07001313 new LocalServiceImpl(mService));
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001314 publishBinderService(Context.INPUT_METHOD_SERVICE, mService);
1315 }
1316
1317 @Override
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001318 public void onSwitchUser(@UserIdInt int userHandle) {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001319 // Called on ActivityManager thread.
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001320 // TODO: Dispatch this to a worker thread as needed.
1321 mService.onSwitchUser(userHandle);
1322 }
1323
1324 @Override
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001325 public void onBootPhase(int phase) {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001326 // Called on ActivityManager thread.
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001327 // TODO: Dispatch this to a worker thread as needed.
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001328 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
1329 StatusBarManagerService statusBarService = (StatusBarManagerService) ServiceManager
1330 .getService(Context.STATUS_BAR_SERVICE);
1331 mService.systemRunning(statusBarService);
1332 }
1333 }
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001334
1335 @Override
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001336 public void onUnlockUser(final @UserIdInt int userHandle) {
1337 // Called on ActivityManager thread.
1338 mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_SYSTEM_UNLOCK_USER,
Fyodor Kupolov0f57cce2016-09-09 10:36:30 -07001339 userHandle /* arg1 */, 0 /* arg2 */));
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001340 }
1341 }
1342
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001343 void onUnlockUser(@UserIdInt int userId) {
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001344 synchronized(mMethodMap) {
1345 final int currentUserId = mSettings.getCurrentUserId();
1346 if (DEBUG) {
1347 Slog.d(TAG, "onUnlockUser: userId=" + userId + " curUserId=" + currentUserId);
1348 }
1349 if (userId != currentUserId) {
1350 return;
1351 }
1352 mSettings.switchCurrentUser(currentUserId, !mSystemReady);
Yohei Yukawa79247822017-01-23 15:26:15 -08001353 if (mSystemReady) {
1354 // We need to rebuild IMEs.
1355 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
1356 updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
1357 }
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001358 }
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001359 }
1360
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001361 void onSwitchUser(@UserIdInt int userId) {
1362 synchronized (mMethodMap) {
1363 switchUserLocked(userId);
1364 }
1365 }
1366
Seigo Nonaka7309b122015-08-17 18:34:13 -07001367 public InputMethodManagerService(Context context) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001368 mIPackageManager = AppGlobals.getPackageManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 mContext = context;
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -08001370 mRes = context.getResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 mHandler = new Handler(this);
Yohei Yukawa81482972015-06-04 00:58:59 -07001372 // Note: SettingsObserver doesn't register observers in its constructor.
1373 mSettingsObserver = new SettingsObserver(mHandler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001374 mIWindowManager = IWindowManager.Stub.asInterface(
1375 ServiceManager.getService(Context.WINDOW_SERVICE));
Seigo Nonaka7309b122015-08-17 18:34:13 -07001376 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
lumarkef1965b2018-09-12 17:42:53 +08001377 final DisplayManagerInternal displayManagerInternal = LocalServices.getService(
1378 DisplayManagerInternal.class);
1379 mImeDisplayValidator = (displayId) -> {
1380 final DisplayInfo displayInfo = displayManagerInternal.getDisplayInfo(displayId);
1381 return displayInfo != null
1382 && (displayInfo.flags & Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0;
1383 };
Mita Yuned218c72012-12-06 17:18:25 -08001384 mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
satoke7c6998e2011-06-03 17:57:59 +09001385 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 public void executeMessage(Message msg) {
1387 handleMessage(msg);
1388 }
Mita Yuned218c72012-12-06 17:18:25 -08001389 }, true /*asyncHandler*/);
Yohei Yukawad34e1482016-02-11 08:03:52 -08001390 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001391 mUserManager = mContext.getSystemService(UserManager.class);
Yohei Yukawa42081402019-01-15 09:57:50 -08001392 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
satok01038492012-04-09 21:08:27 +09001393 mHardKeyboardListener = new HardKeyboardListener();
Dianne Hackborn119bbc32013-03-22 17:27:25 -07001394 mHasFeature = context.getPackageManager().hasSystemFeature(
1395 PackageManager.FEATURE_INPUT_METHODS);
Jason Monk3e189872016-01-12 09:10:34 -05001396 mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
Yohei Yukawafa0e47e2016-04-05 09:55:56 -07001397 mHardKeyboardBehavior = mContext.getResources().getInteger(
1398 com.android.internal.R.integer.config_externalHardKeyboardBehavior);
Tarandeep Singheadb1392018-11-09 18:15:57 +01001399 mIsLowRam = ActivityManager.isLowRamDeviceStatic();
satok7cfc0ed2011-06-20 21:29:36 +09001400
Chris Wren1ce4b6d2015-06-11 10:19:43 -04001401 Bundle extras = new Bundle();
1402 extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001403 @ColorInt final int accentColor = mContext.getColor(
1404 com.android.internal.R.color.system_notification_accent_color);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001405 mImeSwitcherNotification =
1406 new Notification.Builder(mContext, SystemNotificationChannels.VIRTUAL_KEYBOARD)
1407 .setSmallIcon(com.android.internal.R.drawable.ic_notification_ime_default)
1408 .setWhen(0)
1409 .setOngoing(true)
1410 .addExtras(extras)
1411 .setCategory(Notification.CATEGORY_SYSTEM)
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001412 .setColor(accentColor);
Daniel Sandler590d5152012-06-14 16:10:13 -04001413
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001414 Intent intent = new Intent(ACTION_SHOW_INPUT_METHOD_PICKER)
1415 .setPackage(mContext.getPackageName());
satok683e2382011-07-12 08:28:52 +09001416 mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
satokb858c732011-07-22 19:54:34 +09001417
1418 mShowOngoingImeSwitcherForPhones = false;
satok7cfc0ed2011-06-20 21:29:36 +09001419
satok7cfc0ed2011-06-20 21:29:36 +09001420 mNotificationShown = false;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001421 int userId = 0;
1422 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001423 userId = ActivityManager.getService().getCurrentUser().id;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001424 } catch (RemoteException e) {
1425 Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
1426 }
satok913a8922010-08-26 21:53:41 +09001427
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08001428 mLastSwitchUserId = userId;
1429
satokd87c2592010-09-29 11:52:06 +09001430 // mSettings should be created before buildInputMethodListLocked
satokdf31ae62011-01-15 06:19:44 +09001431 mSettings = new InputMethodSettings(
Yohei Yukawaf9277532019-01-25 02:47:32 -08001432 mRes, context.getContentResolver(), mMethodMap, userId, !mSystemReady);
Svet Ganovadc1cf42015-06-15 16:36:24 -07001433
Kenny Guy2a764942014-04-02 13:29:20 +01001434 updateCurrentProfileIds();
Yohei Yukawab557d572018-12-29 21:26:26 -08001435 AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
Yohei Yukawa79247822017-01-23 15:26:15 -08001436 mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
1437 mSettings, context);
satok5b927c432012-05-01 20:09:34 +09001438 }
1439
satok5b927c432012-05-01 20:09:34 +09001440 private void resetDefaultImeLocked(Context context) {
1441 // Do not reset the default (current) IME when it is a 3rd-party IME
Yohei Yukawafd70fe82018-04-08 12:19:56 -07001442 if (mCurMethodId != null && !mMethodMap.get(mCurMethodId).isSystem()) {
satok5b927c432012-05-01 20:09:34 +09001443 return;
1444 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001445 final List<InputMethodInfo> suitableImes = InputMethodUtils.getDefaultEnabledImes(
Yohei Yukawaaf5cee82017-01-23 16:17:11 -08001446 context, mSettings.getEnabledInputMethodListLocked());
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001447 if (suitableImes.isEmpty()) {
1448 Slog.i(TAG, "No default found");
1449 return;
satok5b927c432012-05-01 20:09:34 +09001450 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001451 final InputMethodInfo defIm = suitableImes.get(0);
Yohei Yukawad0332832017-02-01 13:59:43 -08001452 if (DEBUG) {
1453 Slog.i(TAG, "Default found, using " + defIm.getId());
1454 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001455 setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
satok5b927c432012-05-01 20:09:34 +09001456 }
1457
Andreas Gampea36dc622018-02-05 17:19:22 -08001458 @GuardedBy("mMethodMap")
Satoshi Kataoka5ade83b2012-09-26 22:59:41 +09001459 private void switchUserLocked(int newUserId) {
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001460 if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
1461 + " currentUserId=" + mSettings.getCurrentUserId());
1462
Yohei Yukawa81482972015-06-04 00:58:59 -07001463 // ContentObserver should be registered again when the user is changed
1464 mSettingsObserver.registerContentObserverLocked(newUserId);
Yohei Yukawa68645a62016-02-17 07:54:20 -08001465
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001466 // If the system is not ready or the device is not yed unlocked by the user, then we use
1467 // copy-on-write settings.
1468 final boolean useCopyOnWriteSettings =
Yohei Yukawa42081402019-01-15 09:57:50 -08001469 !mSystemReady || !mUserManagerInternal.isUserUnlockingOrUnlocked(newUserId);
Yohei Yukawa68645a62016-02-17 07:54:20 -08001470 mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
Kenny Guy2a764942014-04-02 13:29:20 +01001471 updateCurrentProfileIds();
Yohei Yukawab557d572018-12-29 21:26:26 -08001472 // Additional subtypes should be reset when the user is changed
1473 AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, newUserId);
Satoshi Kataoka7f7535f2013-02-18 12:54:16 +09001474 final String defaultImiId = mSettings.getSelectedInputMethod();
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001475
1476 if (DEBUG) Slog.d(TAG, "Switching user stage 2/3. newUserId=" + newUserId
1477 + " defaultImiId=" + defaultImiId);
1478
Satoshi Kataoka7c4a2a12013-02-25 15:25:43 +09001479 // For secondary users, the list of enabled IMEs may not have been updated since the
1480 // callbacks to PackageMonitor are ignored for the secondary user. Here, defaultImiId may
1481 // not be empty even if the IME has been uninstalled by the primary user.
1482 // Even in such cases, IMMS works fine because it will find the most applicable
1483 // IME for that user.
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001484 final boolean initialUserSwitch = TextUtils.isEmpty(defaultImiId);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001485 mLastSystemLocales = mRes.getConfiguration().getLocales();
1486
1487 // TODO: Is it really possible that switchUserLocked() happens before system ready?
1488 if (mSystemReady) {
1489 hideCurrentInputLocked(0, null);
Yohei Yukawab7526452018-10-21 20:15:17 -07001490 resetCurrentMethodAndClient(UnbindReason.SWITCH_USER);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001491 buildInputMethodListLocked(initialUserSwitch);
1492 if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) {
1493 // This is the first time of the user switch and
1494 // set the current ime to the proper one.
1495 resetDefaultImeLocked(mContext);
1496 }
1497 updateFromSettingsLocked(true);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001498 }
1499
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001500 if (initialUserSwitch) {
Yohei Yukawa094c71f2015-06-20 00:41:31 -07001501 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
1502 mSettings.getEnabledInputMethodListLocked(), newUserId,
1503 mContext.getBasePackageName());
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001504 }
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001505
1506 if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId
1507 + " selectedIme=" + mSettings.getSelectedInputMethod());
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08001508
1509 mLastSwitchUserId = newUserId;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001510 }
1511
Kenny Guy2a764942014-04-02 13:29:20 +01001512 void updateCurrentProfileIds() {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -07001513 mSettings.setCurrentProfileIds(
1514 mUserManager.getProfileIdsWithDisabled(mSettings.getCurrentUserId()));
Amith Yamasani734983f2014-03-04 16:48:05 -08001515 }
1516
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001517 @Override
1518 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1519 throws RemoteException {
1520 try {
1521 return super.onTransact(code, data, reply, flags);
1522 } catch (RuntimeException e) {
1523 // The input method manager only throws security exceptions, so let's
1524 // log all others.
1525 if (!(e instanceof SecurityException)) {
Dianne Hackborn164371f2013-10-01 19:10:13 -07001526 Slog.wtf(TAG, "Input Method Manager Crash", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 }
1528 throw e;
1529 }
1530 }
1531
Svetoslav Ganova0027152013-06-25 14:59:53 -07001532 public void systemRunning(StatusBarManagerService statusBar) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001533 synchronized (mMethodMap) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001534 if (DEBUG) {
1535 Slog.d(TAG, "--- systemReady");
1536 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001537 if (!mSystemReady) {
1538 mSystemReady = true;
Yohei Yukawa79247822017-01-23 15:26:15 -08001539 mLastSystemLocales = mRes.getConfiguration().getLocales();
Yohei Yukawa68645a62016-02-17 07:54:20 -08001540 final int currentUserId = mSettings.getCurrentUserId();
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001541 mSettings.switchCurrentUser(currentUserId,
Yohei Yukawa42081402019-01-15 09:57:50 -08001542 !mUserManagerInternal.isUserUnlockingOrUnlocked(currentUserId));
Yohei Yukawad34e1482016-02-11 08:03:52 -08001543 mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
1544 mNotificationManager = mContext.getSystemService(NotificationManager.class);
Dianne Hackborn661cd522011-08-22 00:26:20 -07001545 mStatusBar = statusBar;
Griff Hazen6090c262016-03-25 08:11:24 -07001546 if (mStatusBar != null) {
1547 mStatusBar.setIconVisibility(mSlotIme, false);
1548 }
Yohei Yukawa849443c2019-01-21 09:02:25 -08001549 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
satokb858c732011-07-22 19:54:34 +09001550 mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
1551 com.android.internal.R.bool.show_ongoing_ime_switcher);
satok01038492012-04-09 21:08:27 +09001552 if (mShowOngoingImeSwitcherForPhones) {
Seigo Nonaka7309b122015-08-17 18:34:13 -07001553 mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
satok01038492012-04-09 21:08:27 +09001554 mHardKeyboardListener);
1555 }
Yohei Yukawa79247822017-01-23 15:26:15 -08001556
1557 mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
1558 mSettingsObserver.registerContentObserverLocked(currentUserId);
1559
1560 final IntentFilter broadcastFilter = new IntentFilter();
1561 broadcastFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
1562 broadcastFilter.addAction(Intent.ACTION_USER_ADDED);
1563 broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
Yohei Yukawa79247822017-01-23 15:26:15 -08001564 broadcastFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001565 broadcastFilter.addAction(ACTION_SHOW_INPUT_METHOD_PICKER);
Yohei Yukawa79247822017-01-23 15:26:15 -08001566 mContext.registerReceiver(new ImmsBroadcastReceiver(), broadcastFilter);
1567
Yohei Yukawa1f9a3cb2017-10-26 15:00:59 -07001568 final String defaultImiId = mSettings.getSelectedInputMethod();
1569 final boolean imeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
1570 buildInputMethodListLocked(!imeSelectedOnBoot /* resetDefaultEnabledIme */);
Yohei Yukawa79247822017-01-23 15:26:15 -08001571 updateFromSettingsLocked(true);
1572 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
1573 mSettings.getEnabledInputMethodListLocked(), currentUserId,
1574 mContext.getBasePackageName());
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001575 }
1576 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001578
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001579 // ---------------------------------------------------------------------------------------
1580 // Check whether or not this is a valid IPC. Assumes an IPC is valid when either
1581 // 1) it comes from the system process
1582 // 2) the calling process' user id is identical to the current user id IMMS thinks.
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001583 @GuardedBy("mMethodMap")
Yohei Yukawa46d74762019-01-22 10:17:22 -08001584 private boolean calledFromValidUserLocked() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001585 final int uid = Binder.getCallingUid();
1586 final int userId = UserHandle.getUserId(uid);
1587 if (DEBUG) {
1588 Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
1589 + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
1590 + " calling userId = " + userId + ", foreground user id = "
Satoshi Kataoka87c29142013-07-31 23:11:54 +09001591 + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid()
1592 + InputMethodUtils.getApiCallStack());
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001593 }
Yohei Yukawaa878b952019-01-10 19:36:24 -08001594 if (uid == Process.SYSTEM_UID) {
1595 return true;
1596 }
1597 if (userId == mSettings.getCurrentUserId()) {
1598 return true;
1599 }
Yohei Yukawa46d74762019-01-22 10:17:22 -08001600 if (!PER_PROFILE_IME_ENABLED && mSettings.isCurrentProfile(userId)) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001601 return true;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001602 }
Satoshi Kataoka135e5fb2012-09-28 18:25:06 +09001603
1604 // Caveat: A process which has INTERACT_ACROSS_USERS_FULL gets results for the
1605 // foreground user, not for the user of that process. Accordingly InputMethodManagerService
1606 // must not manage background users' states in any functions.
1607 // Note that privacy-sensitive IPCs, such as setInputMethod, are still securely guarded
1608 // by a token.
1609 if (mContext.checkCallingOrSelfPermission(
1610 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1611 == PackageManager.PERMISSION_GRANTED) {
1612 if (DEBUG) {
1613 Slog.d(TAG, "--- Access granted because the calling process has "
1614 + "the INTERACT_ACROSS_USERS_FULL permission");
1615 }
1616 return true;
1617 }
Yohei Yukawad0332832017-02-01 13:59:43 -08001618 // TODO(b/34886274): The semantics of this verification is actually not well-defined.
Seigo Nonakae27dc2b2015-08-14 18:21:27 -07001619 Slog.w(TAG, "--- IPC called from background users. Ignore. callers="
1620 + Debug.getCallers(10));
Satoshi Kataoka135e5fb2012-09-28 18:25:06 +09001621 return false;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001622 }
1623
Yohei Yukawa22c97be2014-06-04 19:43:36 +09001624
1625 /**
1626 * Returns true iff the caller is identified to be the current input method with the token.
1627 * @param token The window token given to the input method when it was started.
1628 * @return true if and only if non-null valid token is specified.
1629 */
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08001630 @GuardedBy("mMethodMap")
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08001631 private boolean calledWithValidTokenLocked(@NonNull IBinder token) {
1632 if (token == null) {
1633 throw new InvalidParameterException("token must not be null.");
Yohei Yukawad0332832017-02-01 13:59:43 -08001634 }
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08001635 if (token != mCurToken) {
Yohei Yukawad0332832017-02-01 13:59:43 -08001636 Slog.e(TAG, "Ignoring " + Debug.getCaller() + " due to an invalid token."
1637 + " uid:" + Binder.getCallingUid() + " token:" + token);
Yohei Yukawa22c97be2014-06-04 19:43:36 +09001638 return false;
1639 }
1640 return true;
1641 }
1642
Yohei Yukawaf80087c2018-05-21 09:47:53 -07001643 @GuardedBy("mMethodMap")
1644 private boolean bindCurrentInputMethodServiceLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001645 Intent service, ServiceConnection conn, int flags) {
1646 if (service == null || conn == null) {
1647 Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn);
1648 return false;
1649 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08001650 return mContext.bindServiceAsUser(service, conn, flags,
1651 new UserHandle(mSettings.getCurrentUserId()));
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001652 }
1653
satoke7c6998e2011-06-03 17:57:59 +09001654 @Override
Yohei Yukawad20eef82019-02-05 10:45:32 -08001655 public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
1656 if (UserHandle.getCallingUserId() != userId) {
1657 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
1658 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001659 synchronized (mMethodMap) {
Yohei Yukawad20eef82019-02-05 10:45:32 -08001660 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001661 mSettings.getCurrentUserId(), null);
1662 if (resolvedUserIds.length != 1) {
1663 return Collections.emptyList();
1664 }
1665 final long ident = Binder.clearCallingIdentity();
1666 try {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08001667 return getInputMethodListLocked(resolvedUserIds[0]);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001668 } finally {
1669 Binder.restoreCallingIdentity(ident);
Tarandeep Singh89a6c482017-11-21 14:26:11 -08001670 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 }
1672 }
1673
satoke7c6998e2011-06-03 17:57:59 +09001674 @Override
Yohei Yukawa1fb13c52019-02-05 07:55:28 -08001675 public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
1676 if (UserHandle.getCallingUserId() != userId) {
1677 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
1678 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 synchronized (mMethodMap) {
Yohei Yukawa1fb13c52019-02-05 07:55:28 -08001680 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001681 mSettings.getCurrentUserId(), null);
1682 if (resolvedUserIds.length != 1) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001683 return Collections.emptyList();
1684 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001685 final long ident = Binder.clearCallingIdentity();
1686 try {
1687 return getEnabledInputMethodListLocked(resolvedUserIds[0]);
1688 } finally {
1689 Binder.restoreCallingIdentity(ident);
1690 }
1691 }
1692 }
1693
1694 @GuardedBy("mMethodMap")
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08001695 private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001696 final ArrayList<InputMethodInfo> methodList;
1697 if (userId == mSettings.getCurrentUserId()) {
1698 // Create a copy.
1699 methodList = new ArrayList<>(mMethodList);
1700 } else {
1701 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1702 methodList = new ArrayList<>();
1703 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1704 new ArrayMap<>();
1705 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1706 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1707 methodList);
1708 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001709 return methodList;
1710 }
1711
1712 @GuardedBy("mMethodMap")
1713 private List<InputMethodInfo> getEnabledInputMethodListLocked(@UserIdInt int userId) {
1714 if (userId == mSettings.getCurrentUserId()) {
satokd87c2592010-09-29 11:52:06 +09001715 return mSettings.getEnabledInputMethodListLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001717 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1718 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
1719 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1720 new ArrayMap<>();
1721 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1722 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1723 methodList);
1724 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
Yohei Yukawaf9277532019-01-25 02:47:32 -08001725 mContext.getContentResolver(), methodMap, userId, true);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001726 return settings.getEnabledInputMethodListLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 }
1728
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001729 /**
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001730 * @param imiId if null, returns enabled subtypes for the current imi
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001731 * @return enabled subtypes of the specified imi
1732 */
satoke7c6998e2011-06-03 17:57:59 +09001733 @Override
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001734 public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
satok16331c82010-12-20 23:48:46 +09001735 boolean allowsImplicitlySelectedSubtypes) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001736 final int callingUserId = UserHandle.getCallingUserId();
satok67ddf9c2010-11-17 09:45:54 +09001737 synchronized (mMethodMap) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001738 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
1739 mSettings.getCurrentUserId(), null);
1740 if (resolvedUserIds.length != 1) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001741 return Collections.emptyList();
1742 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001743 final long ident = Binder.clearCallingIdentity();
1744 try {
1745 return getEnabledInputMethodSubtypeListLocked(imiId,
1746 allowsImplicitlySelectedSubtypes, resolvedUserIds[0]);
1747 } finally {
1748 Binder.restoreCallingIdentity(ident);
1749 }
1750 }
1751 }
1752
1753 @GuardedBy("mMethodMap")
1754 private List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(String imiId,
1755 boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) {
1756 if (userId == mSettings.getCurrentUserId()) {
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001757 final InputMethodInfo imi;
1758 if (imiId == null && mCurMethodId != null) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001759 imi = mMethodMap.get(mCurMethodId);
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001760 } else {
1761 imi = mMethodMap.get(imiId);
1762 }
1763 if (imi == null) {
Yohei Yukawab0377bb2015-08-10 21:06:30 -07001764 return Collections.emptyList();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001765 }
1766 return mSettings.getEnabledInputMethodSubtypeListLocked(
1767 mContext, imi, allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +09001768 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001769 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1770 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
1771 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1772 new ArrayMap<>();
1773 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1774 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1775 methodList);
1776 final InputMethodInfo imi = methodMap.get(imiId);
1777 if (imi == null) {
1778 return Collections.emptyList();
1779 }
1780 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
Yohei Yukawaf9277532019-01-25 02:47:32 -08001781 mContext.getContentResolver(), methodMap, userId, true);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001782 return settings.getEnabledInputMethodSubtypeListLocked(
1783 mContext, imi, allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +09001784 }
1785
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001786 /**
1787 * Called by each application process as a preparation to start interacting with
1788 * {@link InputMethodManagerService}.
1789 *
1790 * <p>As a general principle, IPCs from the application process that take
Yohei Yukawa499e3f72018-10-21 20:15:11 -07001791 * {@link IInputMethodClient} will be rejected without this step.</p>
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001792 *
1793 * @param client {@link android.os.Binder} proxy that is associated with the singleton instance
1794 * of {@link android.view.inputmethod.InputMethodManager} that runs on the client
1795 * process
1796 * @param inputContext communication channel for the dummy
1797 * {@link android.view.inputmethod.InputConnection}
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001798 * @param selfReportedDisplayId self-reported display ID to which the client is associated.
1799 * Whether the client is still allowed to access to this display
1800 * or not needs to be evaluated every time the client interacts
1801 * with the display
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001802 */
1803 @Override
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001804 public void addClient(IInputMethodClient client, IInputContext inputContext,
1805 int selfReportedDisplayId) {
Yohei Yukawacb768bc2018-10-24 16:05:09 -07001806 // Here there are two scenarios where this method is called:
1807 // A. IMM is being instantiated in a different process and this is an IPC from that process
1808 // B. IMM is being instantiated in the same process but Binder.clearCallingIdentity() is
1809 // called in the caller side if necessary.
1810 // In either case the following UID/PID should be the ones where InputMethodManager is
1811 // actually running.
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001812 final int callerUid = Binder.getCallingUid();
1813 final int callerPid = Binder.getCallingPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 synchronized (mMethodMap) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001815 // TODO: Optimize this linear search.
Yohei Yukawaac9311e2018-11-20 19:25:23 -08001816 final int numClients = mClients.size();
1817 for (int i = 0; i < numClients; ++i) {
1818 final ClientState state = mClients.valueAt(i);
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001819 if (state.uid == callerUid && state.pid == callerPid
1820 && state.selfReportedDisplayId == selfReportedDisplayId) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001821 throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
Yohei Yukawacb768bc2018-10-24 16:05:09 -07001822 + "/displayId=" + selfReportedDisplayId + " is already registered.");
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001823 }
1824 }
1825 final ClientDeathRecipient deathRecipient = new ClientDeathRecipient(this, client);
1826 try {
1827 client.asBinder().linkToDeath(deathRecipient, 0);
1828 } catch (RemoteException e) {
1829 throw new IllegalStateException(e);
1830 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001831 // We cannot fully avoid race conditions where the client UID already lost the access to
1832 // the given self-reported display ID, even if the client is not maliciously reporting
1833 // a fake display ID. Unconditionally returning SecurityException just because the
1834 // client doesn't pass display ID verification can cause many test failures hence not an
1835 // option right now. At the same time
1836 // context.getSystemService(InputMethodManager.class)
1837 // is expected to return a valid non-null instance at any time if we do not choose to
1838 // have the client crash. Thus we do not verify the display ID at all here. Instead we
1839 // later check the display ID every time the client needs to interact with the specified
1840 // display.
1841 mClients.put(client.asBinder(), new ClientState(client, inputContext, callerUid,
1842 callerPid, selfReportedDisplayId, deathRecipient));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 }
1844 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001845
Yohei Yukawae24ed792018-08-28 19:10:32 -07001846 void removeClient(IInputMethodClient client) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001847 synchronized (mMethodMap) {
Jeff Brownc28867a2013-03-26 15:42:39 -07001848 ClientState cs = mClients.remove(client.asBinder());
1849 if (cs != null) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001850 client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
Jeff Brownc28867a2013-03-26 15:42:39 -07001851 clearClientSessionLocked(cs);
Yohei Yukawa072b1b52015-11-18 15:54:34 -08001852 if (mCurClient == cs) {
Tarandeep Singh93c00cea2018-02-16 14:31:17 -08001853 if (mBoundToMethod) {
1854 mBoundToMethod = false;
1855 if (mCurMethod != null) {
1856 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
1857 MSG_UNBIND_INPUT, mCurMethod));
1858 }
1859 }
Yohei Yukawa072b1b52015-11-18 15:54:34 -08001860 mCurClient = null;
1861 }
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08001862 if (mCurFocusedWindowClient == cs) {
1863 mCurFocusedWindowClient = null;
1864 }
Jeff Brownc28867a2013-03-26 15:42:39 -07001865 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866 }
1867 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001868
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869 void executeOrSendMessage(IInterface target, Message msg) {
1870 if (target.asBinder() instanceof Binder) {
1871 mCaller.sendMessage(msg);
1872 } else {
1873 handleMessage(msg);
1874 msg.recycle();
1875 }
1876 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001877
Yohei Yukawa4afd9332018-10-21 10:43:53 -07001878 void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 if (mCurClient != null) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001880 if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881 + mCurClient.client.asBinder());
1882 if (mBoundToMethod) {
1883 mBoundToMethod = false;
1884 if (mCurMethod != null) {
1885 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
1886 MSG_UNBIND_INPUT, mCurMethod));
1887 }
1888 }
Dianne Hackborna6e41342012-05-22 16:30:34 -07001889
Yohei Yukawa2bc66172017-02-08 11:13:25 -08001890 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
1891 MSG_SET_ACTIVE, 0, 0, mCurClient));
Yohei Yukawa33e81792015-11-17 21:14:42 -08001892 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
1893 MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 mCurClient.sessionRequested = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001895 mCurClient = null;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001896
The Android Open Source Project10592532009-03-18 17:39:46 -07001897 hideInputMethodMenuLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001898 }
1899 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001900
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001901 private int getImeShowFlags() {
1902 int flags = 0;
1903 if (mShowForced) {
1904 flags |= InputMethod.SHOW_FORCED
1905 | InputMethod.SHOW_EXPLICIT;
1906 } else if (mShowExplicitlyRequested) {
1907 flags |= InputMethod.SHOW_EXPLICIT;
1908 }
1909 return flags;
1910 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001912 private int getAppShowFlags() {
1913 int flags = 0;
1914 if (mShowForced) {
1915 flags |= InputMethodManager.SHOW_FORCED;
1916 } else if (!mShowExplicitlyRequested) {
1917 flags |= InputMethodManager.SHOW_IMPLICIT;
1918 }
1919 return flags;
1920 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001921
Andreas Gampea36dc622018-02-05 17:19:22 -08001922 @GuardedBy("mMethodMap")
Yohei Yukawa2553e482017-12-15 15:47:33 -08001923 @NonNull
Yohei Yukawadc66e522018-10-21 10:43:14 -07001924 InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001925 if (!mBoundToMethod) {
1926 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
1927 MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
1928 mBoundToMethod = true;
1929 }
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08001930
1931 final Binder startInputToken = new Binder();
Yohei Yukawa7979e1a2019-02-12 02:01:10 -08001932 final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), mCurToken,
1933 mCurTokenDisplayId, mCurId, startInputReason, !initial,
1934 UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId,
1935 mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, mCurSeq);
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07001936 mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
Yohei Yukawa357b2f62017-02-14 09:40:03 -08001937 mStartInputHistory.addEntry(info);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08001938
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001939 final SessionState session = mCurClient.curSession;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08001940 executeOrSendMessage(session.method, mCaller.obtainMessageIIOOOO(
Yohei Yukawaf7526b52017-02-11 20:57:10 -08001941 MSG_START_INPUT, mCurInputContextMissingMethods, initial ? 0 : 1 /* restarting */,
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08001942 startInputToken, session, mCurInputContext, mCurAttribute));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001943 if (mShowRequested) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001944 if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
The Android Open Source Project4df24232009-03-05 14:34:35 -08001945 showCurrentInputLocked(getAppShowFlags(), null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001946 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08001947 return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
1948 session.session, (session.channel != null ? session.channel.dup() : null),
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07001949 mCurId, mCurSeq);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001950 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001951
Andreas Gampea36dc622018-02-05 17:19:22 -08001952 @GuardedBy("mMethodMap")
Yohei Yukawa2553e482017-12-15 15:47:33 -08001953 @NonNull
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001954 InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07001955 @MissingMethodFlags int missingMethods, @NonNull EditorInfo attribute,
1956 @StartInputFlags int startInputFlags, @StartInputReason int startInputReason) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08001957 // If no method is currently selected, do nothing.
1958 if (mCurMethodId == null) {
Yohei Yukawa2553e482017-12-15 15:47:33 -08001959 return InputBindResult.NO_IME;
Dianne Hackborn7663d802012-02-24 13:08:49 -08001960 }
1961
Yohei Yukawa0deaef02018-10-17 10:33:48 +08001962 if (!mSystemReady) {
1963 // If the system is not yet ready, we shouldn't be running third
1964 // party code.
1965 return new InputBindResult(
1966 InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
1967 null, null, mCurMethodId, mCurSeq);
1968 }
1969
Yohei Yukawad57ba672015-06-08 16:39:46 -07001970 if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
1971 attribute.packageName)) {
1972 Slog.e(TAG, "Rejecting this client as it reported an invalid package name."
1973 + " uid=" + cs.uid + " package=" + attribute.packageName);
Yohei Yukawa2553e482017-12-15 15:47:33 -08001974 return InputBindResult.INVALID_PACKAGE_NAME;
Yohei Yukawa0f3ad12015-04-06 16:48:24 -07001975 }
1976
Yohei Yukawa0deaef02018-10-17 10:33:48 +08001977 if (!mWindowManagerInternal.isUidAllowedOnDisplay(cs.selfReportedDisplayId, cs.uid)) {
1978 // Wait, the client no longer has access to the display.
1979 return InputBindResult.INVALID_DISPLAY_ID;
1980 }
lumarkef1965b2018-09-12 17:42:53 +08001981 // Compute the final shown display ID with validated cs.selfReportedDisplayId for this
1982 // session & other conditions.
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08001983 final int displayIdToShowIme = computeImeDisplayIdForTarget(cs.selfReportedDisplayId,
1984 mImeDisplayValidator);
Yohei Yukawa0deaef02018-10-17 10:33:48 +08001985
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001986 if (mCurClient != cs) {
John Spurlocke0980502013-10-25 11:59:29 -04001987 // Was the keyguard locked when switching over to the new client?
1988 mCurClientInKeyguard = isKeyguardLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001989 // If the client is changing, we need to switch over to the new
1990 // one.
Yohei Yukawab7526452018-10-21 20:15:17 -07001991 unbindCurrentClientLocked(UnbindReason.SWITCH_CLIENT);
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001992 if (DEBUG) Slog.v(TAG, "switching to client: client="
John Spurlocke0980502013-10-25 11:59:29 -04001993 + cs.client.asBinder() + " keyguard=" + mCurClientInKeyguard);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994
1995 // If the screen is on, inform the new client it is active
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07001996 if (mIsInteractive) {
tiansiming [田思明]e102c972018-04-17 18:15:33 +08001997 executeOrSendMessage(cs.client, mCaller.obtainMessageIO(MSG_SET_ACTIVE, 1, cs));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001998 }
1999 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002000
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002001 // Bump up the sequence for this client and attach it.
2002 mCurSeq++;
2003 if (mCurSeq <= 0) mCurSeq = 1;
2004 mCurClient = cs;
2005 mCurInputContext = inputContext;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07002006 mCurInputContextMissingMethods = missingMethods;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007 mCurAttribute = attribute;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002008
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002009 // Check if the input method is changing.
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002010 // We expect the caller has already verified that the client is allowed to access this
2011 // display ID.
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002012 if (mCurId != null && mCurId.equals(mCurMethodId)
2013 && displayIdToShowIme == mCurTokenDisplayId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002014 if (cs.curSession != null) {
2015 // Fast case: if we are already connected to the input method,
2016 // then just return it.
Yohei Yukawa87ca8402017-02-07 00:13:14 -08002017 return attachNewInputLocked(startInputReason,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002018 (startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 }
2020 if (mHaveConnection) {
2021 if (mCurMethod != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002022 // Return to client, and we will get back with it when
2023 // we have had a session made for it.
Jeff Brownc28867a2013-03-26 15:42:39 -07002024 requestClientSessionLocked(cs);
Yohei Yukawa2553e482017-12-15 15:47:33 -08002025 return new InputBindResult(
2026 InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07002027 null, null, mCurId, mCurSeq);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002028 } else if (SystemClock.uptimeMillis()
2029 < (mLastBindTime+TIME_TO_RECONNECT)) {
2030 // In this case we have connected to the service, but
2031 // don't yet have its interface. If it hasn't been too
2032 // long since we did the connection, we'll return to
2033 // the client and wait to get the service interface so
2034 // we can report back. If it has been too long, we want
2035 // to fall through so we can try a disconnect/reconnect
2036 // to see if we can get back in touch with the service.
Yohei Yukawa2553e482017-12-15 15:47:33 -08002037 return new InputBindResult(
2038 InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07002039 null, null, mCurId, mCurSeq);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002040 } else {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002041 EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
2042 mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002043 }
2044 }
2045 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002047 InputMethodInfo info = mMethodMap.get(mCurMethodId);
2048 if (info == null) {
2049 throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
2050 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002051
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002052 unbindCurrentMethodLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
2055 mCurIntent.setComponent(info.getComponent());
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07002056 mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
2057 com.android.internal.R.string.input_method_binding_label);
2058 mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
2059 mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002060
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002061 if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002062 mLastBindTime = SystemClock.uptimeMillis();
2063 mHaveConnection = true;
2064 mCurId = info.getId();
2065 mCurToken = new Binder();
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002066 mCurTokenDisplayId = displayIdToShowIme;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 try {
lumark90120a82018-08-15 00:33:03 +08002068 if (DEBUG) {
2069 Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
2070 + mCurTokenDisplayId);
2071 }
Yohei Yukawa6e875592019-01-28 00:49:30 -08002072 mIWindowManager.addWindowToken(mCurToken, LayoutParams.TYPE_INPUT_METHOD,
2073 mCurTokenDisplayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002074 } catch (RemoteException e) {
2075 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002076 return new InputBindResult(
2077 InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07002078 null, null, mCurId, mCurSeq);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002079 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002080 mCurIntent = null;
2081 Slog.w(TAG, "Failure connecting to input method service: " + mCurIntent);
2082 return InputBindResult.IME_NOT_CONNECTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002084
lumarkef1965b2018-09-12 17:42:53 +08002085 @FunctionalInterface
2086 interface ImeDisplayValidator {
2087 boolean displayCanShowIme(int displayId);
2088 }
2089
2090 /**
2091 * Find the display where the IME should be shown.
2092 *
2093 * @param displayId the ID of the display where the IME client target is.
lumarkef1965b2018-09-12 17:42:53 +08002094 * @param checker instance of {@link ImeDisplayValidator} which is used for
2095 * checking display config to adjust the final target display.
2096 * @return The ID of the display where the IME should be shown.
2097 */
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08002098 static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
lumarkef1965b2018-09-12 17:42:53 +08002099 if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
2100 // We always assume that the default display id suitable to show the IME window.
2101 return DEFAULT_DISPLAY;
2102 }
2103 // Show IME in default display when the display with IME target doesn't support system
2104 // decorations.
2105 return checker.displayCanShowIme(displayId) ? displayId : DEFAULT_DISPLAY;
2106 }
2107
satoke7c6998e2011-06-03 17:57:59 +09002108 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002109 public void onServiceConnected(ComponentName name, IBinder service) {
2110 synchronized (mMethodMap) {
2111 if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
2112 mCurMethod = IInputMethod.Stub.asInterface(service);
Dianne Hackborncc278702009-09-02 23:07:23 -07002113 if (mCurToken == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002114 Slog.w(TAG, "Service connected without a token!");
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002115 unbindCurrentMethodLocked();
Dianne Hackborncc278702009-09-02 23:07:23 -07002116 return;
2117 }
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002118 if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
lumark90120a82018-08-15 00:33:03 +08002119 // Dispatch display id for InputMethodService to update context display.
2120 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
2121 MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002122 if (mCurClient != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002123 clearClientSessionLocked(mCurClient);
2124 requestClientSessionLocked(mCurClient);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002125 }
2126 }
2127 }
2128 }
2129
Jeff Brownc28867a2013-03-26 15:42:39 -07002130 void onSessionCreated(IInputMethod method, IInputMethodSession session,
2131 InputChannel channel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 synchronized (mMethodMap) {
2133 if (mCurMethod != null && method != null
2134 && mCurMethod.asBinder() == method.asBinder()) {
2135 if (mCurClient != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002136 clearClientSessionLocked(mCurClient);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002137 mCurClient.curSession = new SessionState(mCurClient,
Jeff Brownc28867a2013-03-26 15:42:39 -07002138 method, session, channel);
Yohei Yukawa87ca8402017-02-07 00:13:14 -08002139 InputBindResult res = attachNewInputLocked(
Yohei Yukawa42194222018-10-21 20:14:40 -07002140 StartInputReason.SESSION_CREATED_BY_IME, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002141 if (res.method != null) {
2142 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
Yohei Yukawa33e81792015-11-17 21:14:42 -08002143 MSG_BIND_CLIENT, mCurClient.client, res));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002144 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002145 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002146 }
2147 }
2148 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002149
2150 // Session abandoned. Close its associated input channel.
2151 channel.dispose();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002153
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002154 void unbindCurrentMethodLocked() {
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002155 if (mVisibleBound) {
2156 mContext.unbindService(mVisibleConnection);
2157 mVisibleBound = false;
2158 }
2159
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002160 if (mHaveConnection) {
2161 mContext.unbindService(this);
2162 mHaveConnection = false;
2163 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002164
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002165 if (mCurToken != null) {
2166 try {
lumark90120a82018-08-15 00:33:03 +08002167 if (DEBUG) {
2168 Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
2169 + mCurTokenDisplayId);
2170 }
lumark90120a82018-08-15 00:33:03 +08002171 mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002172 } catch (RemoteException e) {
2173 }
2174 mCurToken = null;
lumark90120a82018-08-15 00:33:03 +08002175 mCurTokenDisplayId = INVALID_DISPLAY;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002176 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002177
The Android Open Source Project10592532009-03-18 17:39:46 -07002178 mCurId = null;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002179 clearCurMethodLocked();
Yohei Yukawabc7b5262015-11-17 17:38:41 -08002180 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002181
Yohei Yukawa4afd9332018-10-21 10:43:53 -07002182 void resetCurrentMethodAndClient(@UnbindReason int unbindClientReason) {
Yohei Yukawabc7b5262015-11-17 17:38:41 -08002183 mCurMethodId = null;
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002184 unbindCurrentMethodLocked();
Yohei Yukawa33e81792015-11-17 21:14:42 -08002185 unbindCurrentClientLocked(unbindClientReason);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002186 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002187
2188 void requestClientSessionLocked(ClientState cs) {
2189 if (!cs.sessionRequested) {
2190 if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
2191 InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString());
2192 cs.sessionRequested = true;
2193 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOOO(
2194 MSG_CREATE_SESSION, mCurMethod, channels[1],
2195 new MethodCallback(this, mCurMethod, channels[0])));
2196 }
2197 }
2198
2199 void clearClientSessionLocked(ClientState cs) {
2200 finishSessionLocked(cs.curSession);
2201 cs.curSession = null;
2202 cs.sessionRequested = false;
2203 }
2204
2205 private void finishSessionLocked(SessionState sessionState) {
2206 if (sessionState != null) {
2207 if (sessionState.session != null) {
2208 try {
2209 sessionState.session.finishSession();
2210 } catch (RemoteException e) {
2211 Slog.w(TAG, "Session failed to close due to remote exception", e);
Yohei Yukawa849443c2019-01-21 09:02:25 -08002212 updateSystemUiLocked(0 /* vis */, mBackDisposition);
Jeff Brownc28867a2013-03-26 15:42:39 -07002213 }
2214 sessionState.session = null;
2215 }
2216 if (sessionState.channel != null) {
2217 sessionState.channel.dispose();
2218 sessionState.channel = null;
Devin Taylor0c33ed22010-02-23 13:26:46 -06002219 }
2220 }
2221 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002222
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002223 void clearCurMethodLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002224 if (mCurMethod != null) {
Yohei Yukawaac9311e2018-11-20 19:25:23 -08002225 final int numClients = mClients.size();
2226 for (int i = 0; i < numClients; ++i) {
2227 clearClientSessionLocked(mClients.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002228 }
Devin Taylor0c33ed22010-02-23 13:26:46 -06002229
Jeff Brownc28867a2013-03-26 15:42:39 -07002230 finishSessionLocked(mEnabledSession);
Devin Taylor0c33ed22010-02-23 13:26:46 -06002231 mEnabledSession = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002232 mCurMethod = null;
2233 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002234 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002235 mStatusBar.setIconVisibility(mSlotIme, false);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002236 }
Yohei Yukawa2bc66172017-02-08 11:13:25 -08002237 mInFullscreenMode = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002238 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002239
satoke7c6998e2011-06-03 17:57:59 +09002240 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002241 public void onServiceDisconnected(ComponentName name) {
Yohei Yukawa817d5f72017-01-04 20:15:02 -08002242 // Note that mContext.unbindService(this) does not trigger this. Hence if we are here the
2243 // disconnection is not intended by IMMS (e.g. triggered because the current IMS crashed),
2244 // which is irregular but can eventually happen for everyone just by continuing using the
2245 // device. Thus it is important to make sure that all the internal states are properly
2246 // refreshed when this method is called back. Running
2247 // adb install -r <APK that implements the current IME>
2248 // would be a good way to trigger such a situation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002249 synchronized (mMethodMap) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002250 if (DEBUG) Slog.v(TAG, "Service disconnected: " + name
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002251 + " mCurIntent=" + mCurIntent);
2252 if (mCurMethod != null && mCurIntent != null
2253 && name.equals(mCurIntent.getComponent())) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002254 clearCurMethodLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002255 // We consider this to be a new bind attempt, since the system
2256 // should now try to restart the service for us.
2257 mLastBindTime = SystemClock.uptimeMillis();
2258 mShowRequested = mInputShown;
2259 mInputShown = false;
Yohei Yukawab7526452018-10-21 20:15:17 -07002260 unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002261 }
2262 }
2263 }
2264
Yohei Yukawaeec552e2018-09-09 20:48:41 -07002265 @BinderThread
Yohei Yukawa41b094f2018-09-09 23:58:45 -07002266 private void updateStatusIcon(@NonNull IBinder token, String packageName,
2267 @DrawableRes int iconId) {
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002268 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002269 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002270 return;
2271 }
2272 final long ident = Binder.clearCallingIdentity();
2273 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002274 if (iconId == 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002275 if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
Dianne Hackborn661cd522011-08-22 00:26:20 -07002276 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002277 mStatusBar.setIconVisibility(mSlotIme, false);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002278 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002279 } else if (packageName != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002280 if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002281 CharSequence contentDescription = null;
2282 try {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002283 // Use PackageManager to load label
2284 final PackageManager packageManager = mContext.getPackageManager();
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002285 contentDescription = packageManager.getApplicationLabel(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002286 mIPackageManager.getApplicationInfo(packageName, 0,
2287 mSettings.getCurrentUserId()));
2288 } catch (RemoteException e) {
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002289 /* ignore */
2290 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002291 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002292 mStatusBar.setIcon(mSlotIme, packageName, iconId, 0,
Dianne Hackborn661cd522011-08-22 00:26:20 -07002293 contentDescription != null
2294 ? contentDescription.toString() : null);
Jason Monk3e189872016-01-12 09:10:34 -05002295 mStatusBar.setIconVisibility(mSlotIme, true);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002296 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002297 }
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002298 } finally {
2299 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002301 }
2302 }
2303
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002304 private boolean shouldShowImeSwitcherLocked(int visibility) {
satok7cfc0ed2011-06-20 21:29:36 +09002305 if (!mShowOngoingImeSwitcherForPhones) return false;
Jason Monk807ef762014-05-08 15:47:46 -04002306 if (mSwitchingDialog != null) return false;
Yohei Yukawad2bc3092017-07-31 15:37:14 -07002307 if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
2308 && mKeyguardManager != null && mKeyguardManager.isKeyguardSecure()) return false;
Tarandeep Singheadb1392018-11-09 18:15:57 +01002309 if ((visibility & InputMethodService.IME_ACTIVE) == 0
2310 || (visibility & InputMethodService.IME_INVISIBLE) != 0) {
2311 return false;
2312 }
Seigo Nonaka7309b122015-08-17 18:34:13 -07002313 if (mWindowManagerInternal.isHardKeyboardAvailable()) {
Yohei Yukawafa0e47e2016-04-05 09:55:56 -07002314 if (mHardKeyboardBehavior == HardKeyboardBehavior.WIRELESS_AFFORDANCE) {
2315 // When physical keyboard is attached, we show the ime switcher (or notification if
2316 // NavBar is not available) because SHOW_IME_WITH_HARD_KEYBOARD settings currently
2317 // exists in the IME switcher dialog. Might be OK to remove this condition once
2318 // SHOW_IME_WITH_HARD_KEYBOARD settings finds a good place to live.
2319 return true;
2320 }
Yohei Yukawa89398382016-03-29 11:37:04 -07002321 } else if ((visibility & InputMethodService.IME_VISIBLE) == 0) {
2322 return false;
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002323 }
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002324
2325 List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
2326 final int N = imis.size();
2327 if (N > 2) return true;
2328 if (N < 1) return false;
2329 int nonAuxCount = 0;
2330 int auxCount = 0;
2331 InputMethodSubtype nonAuxSubtype = null;
2332 InputMethodSubtype auxSubtype = null;
2333 for(int i = 0; i < N; ++i) {
2334 final InputMethodInfo imi = imis.get(i);
2335 final List<InputMethodSubtype> subtypes =
2336 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
2337 final int subtypeCount = subtypes.size();
2338 if (subtypeCount == 0) {
2339 ++nonAuxCount;
2340 } else {
2341 for (int j = 0; j < subtypeCount; ++j) {
2342 final InputMethodSubtype subtype = subtypes.get(j);
2343 if (!subtype.isAuxiliary()) {
2344 ++nonAuxCount;
2345 nonAuxSubtype = subtype;
2346 } else {
2347 ++auxCount;
2348 auxSubtype = subtype;
satok7cfc0ed2011-06-20 21:29:36 +09002349 }
2350 }
satok7cfc0ed2011-06-20 21:29:36 +09002351 }
2352 }
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002353 if (nonAuxCount > 1 || auxCount > 1) {
2354 return true;
2355 } else if (nonAuxCount == 1 && auxCount == 1) {
2356 if (nonAuxSubtype != null && auxSubtype != null
2357 && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
2358 || auxSubtype.overridesImplicitlyEnabledSubtype()
2359 || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
2360 && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
2361 return false;
2362 }
2363 return true;
2364 }
2365 return false;
satok7cfc0ed2011-06-20 21:29:36 +09002366 }
2367
John Spurlocke0980502013-10-25 11:59:29 -04002368 private boolean isKeyguardLocked() {
2369 return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
2370 }
2371
Yohei Yukawad6475a62017-04-17 10:35:27 -07002372 @BinderThread
satokdbf29502011-08-25 15:28:23 +09002373 @SuppressWarnings("deprecation")
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08002374 private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002375 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002376 if (!calledWithValidTokenLocked(token)) {
2377 return;
2378 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002379 mImeWindowVis = vis;
2380 mBackDisposition = backDisposition;
Yohei Yukawa849443c2019-01-21 09:02:25 -08002381 updateSystemUiLocked(vis, backDisposition);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002382 }
Yohei Yukawad6475a62017-04-17 10:35:27 -07002383
2384 final boolean dismissImeOnBackKeyPressed;
2385 switch (backDisposition) {
2386 case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
2387 dismissImeOnBackKeyPressed = true;
2388 break;
2389 case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
2390 dismissImeOnBackKeyPressed = false;
2391 break;
2392 default:
2393 case InputMethodService.BACK_DISPOSITION_DEFAULT:
2394 dismissImeOnBackKeyPressed = ((vis & InputMethodService.IME_VISIBLE) != 0);
2395 break;
2396 }
Yohei Yukawaee2a7ed2017-02-15 21:38:57 -08002397 mWindowManagerInternal.updateInputMethodWindowStatus(token,
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002398 (vis & InputMethodService.IME_VISIBLE) != 0, dismissImeOnBackKeyPressed);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002399 }
2400
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002401 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08002402 private void reportStartInput(@NonNull IBinder token, IBinder startInputToken) {
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002403 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002404 if (!calledWithValidTokenLocked(token)) {
2405 return;
2406 }
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002407 final IBinder targetWindow = mImeTargetWindowMap.get(startInputToken);
2408 if (targetWindow != null && mLastImeTargetWindow != targetWindow) {
2409 mWindowManagerInternal.updateInputMethodTargetWindow(token, targetWindow);
2410 }
2411 mLastImeTargetWindow = targetWindow;
2412 }
2413 }
2414
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002415 // Caution! This method is called in this class. Handle multi-user carefully
Yohei Yukawa849443c2019-01-21 09:02:25 -08002416 private void updateSystemUiLocked(int vis, int backDisposition) {
2417 if (mCurToken == null) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002418 return;
2419 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01002420 if (DEBUG) {
2421 Slog.d(TAG, "IME window vis: " + vis
2422 + " active: " + (vis & InputMethodService.IME_ACTIVE)
2423 + " inv: " + (vis & InputMethodService.IME_INVISIBLE));
2424 }
2425
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002426 // TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
2427 // all updateSystemUi happens on system previlege.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002428 final long ident = Binder.clearCallingIdentity();
satok06487a52010-10-29 11:37:18 +09002429 try {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002430 // apply policy for binder calls
2431 if (vis != 0 && isKeyguardLocked() && !mCurClientInKeyguard) {
2432 vis = 0;
satok06487a52010-10-29 11:37:18 +09002433 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002434 // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
2435 final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
2436 if (mStatusBar != null) {
Yohei Yukawa849443c2019-01-21 09:02:25 -08002437 mStatusBar.setImeWindowStatus(mCurToken, vis, backDisposition,
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002438 needsToShowImeSwitcher);
2439 }
2440 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
2441 if (imi != null && needsToShowImeSwitcher) {
2442 // Used to load label
2443 final CharSequence title = mRes.getText(
2444 com.android.internal.R.string.select_input_method);
2445 final CharSequence summary = InputMethodUtils.getImeAndSubtypeDisplayName(
2446 mContext, imi, mCurrentSubtype);
Chris Wren1ce4b6d2015-06-11 10:19:43 -04002447 mImeSwitcherNotification.setContentTitle(title)
2448 .setContentText(summary)
2449 .setContentIntent(mImeSwitchPendingIntent);
Seigo Nonaka7309b122015-08-17 18:34:13 -07002450 try {
Charles Chenea6e7f02018-11-19 21:37:45 +08002451 // TODO(b/120076400): Figure out what is the best behavior
Seigo Nonaka7309b122015-08-17 18:34:13 -07002452 if ((mNotificationManager != null)
Charles Chenea6e7f02018-11-19 21:37:45 +08002453 && !mIWindowManager.hasNavigationBar(DEFAULT_DISPLAY)) {
Seigo Nonaka7309b122015-08-17 18:34:13 -07002454 if (DEBUG) {
2455 Slog.d(TAG, "--- show notification: label = " + summary);
2456 }
2457 mNotificationManager.notifyAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04002458 SystemMessage.NOTE_SELECT_INPUT_METHOD,
Seigo Nonaka7309b122015-08-17 18:34:13 -07002459 mImeSwitcherNotification.build(), UserHandle.ALL);
2460 mNotificationShown = true;
Dianne Hackborn661cd522011-08-22 00:26:20 -07002461 }
Seigo Nonaka7309b122015-08-17 18:34:13 -07002462 } catch (RemoteException e) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002463 }
2464 } else {
2465 if (mNotificationShown && mNotificationManager != null) {
2466 if (DEBUG) {
2467 Slog.d(TAG, "--- hide notification");
satok7cfc0ed2011-06-20 21:29:36 +09002468 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002469 mNotificationManager.cancelAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04002470 SystemMessage.NOTE_SELECT_INPUT_METHOD, UserHandle.ALL);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002471 mNotificationShown = false;
satok7cfc0ed2011-06-20 21:29:36 +09002472 }
satok06487a52010-10-29 11:37:18 +09002473 }
2474 } finally {
2475 Binder.restoreCallingIdentity(ident);
2476 }
2477 }
2478
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002479 void updateFromSettingsLocked(boolean enabledMayChange) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07002480 updateInputMethodsFromSettingsLocked(enabledMayChange);
2481 updateKeyboardFromSettingsLocked();
2482 }
2483
2484 void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002485 if (enabledMayChange) {
2486 List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
2487 for (int i=0; i<enabled.size(); i++) {
2488 // We allow the user to select "disabled until used" apps, so if they
2489 // are enabling one of those here we now need to make it enabled.
2490 InputMethodInfo imm = enabled.get(i);
2491 try {
2492 ApplicationInfo ai = mIPackageManager.getApplicationInfo(imm.getPackageName(),
2493 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
2494 mSettings.getCurrentUserId());
Satoshi Kataoka7987a312013-04-17 18:59:33 +09002495 if (ai != null && ai.enabledSetting
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002496 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09002497 if (DEBUG) {
2498 Slog.d(TAG, "Update state(" + imm.getId()
2499 + "): DISABLED_UNTIL_USED -> DEFAULT");
2500 }
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002501 mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
2502 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
Dianne Hackborn3fa3c28a2013-03-26 16:15:41 -07002503 PackageManager.DONT_KILL_APP, mSettings.getCurrentUserId(),
2504 mContext.getBasePackageName());
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002505 }
2506 } catch (RemoteException e) {
2507 }
2508 }
2509 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002510 // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and
2511 // ENABLED_INPUT_METHODS is taking care of keeping them correctly in
2512 // sync, so we will never have a DEFAULT_INPUT_METHOD that is not
2513 // enabled.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002514 String id = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09002515 // There is no input method selected, try to choose new applicable input method.
2516 if (TextUtils.isEmpty(id) && chooseNewDefaultIMELocked()) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002517 id = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09002518 }
2519 if (!TextUtils.isEmpty(id)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002520 try {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09002521 setInputMethodLocked(id, mSettings.getSelectedInputMethodSubtypeId(id));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002522 } catch (IllegalArgumentException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002523 Slog.w(TAG, "Unknown input method from prefs: " + id, e);
Yohei Yukawab7526452018-10-21 20:15:17 -07002524 resetCurrentMethodAndClient(UnbindReason.SWITCH_IME_FAILED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002525 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002526 } else {
2527 // There is no longer an input method set, so stop any current one.
Yohei Yukawab7526452018-10-21 20:15:17 -07002528 resetCurrentMethodAndClient(UnbindReason.NO_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002529 }
Yohei Yukawa3d46bab2014-05-30 18:10:18 +09002530 // Here is not the perfect place to reset the switching controller. Ideally
2531 // mSwitchingController and mSettings should be able to share the same state.
2532 // TODO: Make sure that mSwitchingController and mSettings are sharing the
2533 // the same enabled IMEs list.
2534 mSwitchingController.resetCircularListLocked(mContext);
Michael Wright7b5a96b2014-08-09 19:28:42 -07002535
2536 }
2537
2538 public void updateKeyboardFromSettingsLocked() {
2539 mShowImeWithHardKeyboard = mSettings.isShowImeWithHardKeyboardEnabled();
2540 if (mSwitchingDialog != null
2541 && mSwitchingDialogTitleView != null
2542 && mSwitchingDialog.isShowing()) {
2543 final Switch hardKeySwitch = (Switch)mSwitchingDialogTitleView.findViewById(
2544 com.android.internal.R.id.hard_keyboard_switch);
2545 hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
2546 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002547 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002548
satokab751aa2010-09-14 19:17:36 +09002549 /* package */ void setInputMethodLocked(String id, int subtypeId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002550 InputMethodInfo info = mMethodMap.get(id);
2551 if (info == null) {
satok913a8922010-08-26 21:53:41 +09002552 throw new IllegalArgumentException("Unknown id: " + id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002553 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002554
satokd81e9502012-05-21 12:58:45 +09002555 // See if we need to notify a subtype change within the same IME.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002556 if (id.equals(mCurMethodId)) {
satokd81e9502012-05-21 12:58:45 +09002557 final int subtypeCount = info.getSubtypeCount();
2558 if (subtypeCount <= 0) {
2559 return;
satokcd7cd292010-11-20 15:46:23 +09002560 }
satokd81e9502012-05-21 12:58:45 +09002561 final InputMethodSubtype oldSubtype = mCurrentSubtype;
2562 final InputMethodSubtype newSubtype;
2563 if (subtypeId >= 0 && subtypeId < subtypeCount) {
2564 newSubtype = info.getSubtypeAt(subtypeId);
2565 } else {
2566 // If subtype is null, try to find the most applicable one from
2567 // getCurrentInputMethodSubtype.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002568 newSubtype = getCurrentInputMethodSubtypeLocked();
satokd81e9502012-05-21 12:58:45 +09002569 }
2570 if (newSubtype == null || oldSubtype == null) {
2571 Slog.w(TAG, "Illegal subtype state: old subtype = " + oldSubtype
2572 + ", new subtype = " + newSubtype);
2573 return;
2574 }
2575 if (newSubtype != oldSubtype) {
2576 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
2577 if (mCurMethod != null) {
2578 try {
Yohei Yukawa849443c2019-01-21 09:02:25 -08002579 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
satokd81e9502012-05-21 12:58:45 +09002580 mCurMethod.changeInputMethodSubtype(newSubtype);
2581 } catch (RemoteException e) {
2582 Slog.w(TAG, "Failed to call changeInputMethodSubtype");
satokab751aa2010-09-14 19:17:36 +09002583 }
2584 }
2585 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002586 return;
2587 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002588
satokd81e9502012-05-21 12:58:45 +09002589 // Changing to a different IME.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002590 final long ident = Binder.clearCallingIdentity();
2591 try {
satokab751aa2010-09-14 19:17:36 +09002592 // Set a subtype to this input method.
2593 // subtypeId the name of a subtype which will be set.
satok723a27e2010-11-11 14:58:11 +09002594 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, false);
2595 // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
2596 // because mCurMethodId is stored as a history in
2597 // setSelectedInputMethodAndSubtypeLocked().
2598 mCurMethodId = id;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002599
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07002600 if (LocalServices.getService(ActivityManagerInternal.class).isSystemReady()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002601 Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08002602 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002603 intent.putExtra("input_method_id", id);
Amith Yamasanicd757062012-10-19 18:23:52 -07002604 mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002605 }
Yohei Yukawab7526452018-10-21 20:15:17 -07002606 unbindCurrentClientLocked(UnbindReason.SWITCH_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002607 } finally {
2608 Binder.restoreCallingIdentity(ident);
2609 }
2610 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002611
satok42c5a162011-05-26 16:46:14 +09002612 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -08002613 public boolean showSoftInput(IInputMethodClient client, int flags,
2614 ResultReceiver resultReceiver) {
Dianne Hackborncef65ee2010-09-30 18:27:22 -07002615 int uid = Binder.getCallingUid();
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002616 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08002617 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002618 return false;
2619 }
2620 final long ident = Binder.clearCallingIdentity();
2621 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002622 if (mCurClient == null || client == null
2623 || mCurClient.client.asBinder() != client.asBinder()) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002624 // We need to check if this is the current client with
2625 // focus in the window manager, to allow this call to
2626 // be made before input is started in it.
Yohei Yukawa41f89c32018-09-19 14:30:04 -07002627 final ClientState cs = mClients.get(client.asBinder());
2628 if (cs == null) {
2629 throw new IllegalArgumentException("unknown client " + client.asBinder());
2630 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002631 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
2632 cs.selfReportedDisplayId)) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002633 Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002634 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002635 }
2636 }
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002637 if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
The Android Open Source Project4df24232009-03-05 14:34:35 -08002638 return showCurrentInputLocked(flags, resultReceiver);
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002639 } finally {
2640 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002641 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002642 }
2643 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002644
Andreas Gamped6d42062018-07-20 13:08:21 -07002645 @GuardedBy("mMethodMap")
The Android Open Source Project4df24232009-03-05 14:34:35 -08002646 boolean showCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647 mShowRequested = true;
Anna Galusza9b278112016-01-04 11:37:37 -08002648 if (mAccessibilityRequestingNoSoftKeyboard) {
2649 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002650 }
Anna Galusza9b278112016-01-04 11:37:37 -08002651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002652 if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
2653 mShowExplicitlyRequested = true;
2654 mShowForced = true;
Anna Galusza9b278112016-01-04 11:37:37 -08002655 } else if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
2656 mShowExplicitlyRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002658
Dianne Hackborncc278702009-09-02 23:07:23 -07002659 if (!mSystemReady) {
2660 return false;
2661 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002662
The Android Open Source Project4df24232009-03-05 14:34:35 -08002663 boolean res = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002664 if (mCurMethod != null) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002665 if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + mCurToken);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002666 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
2667 MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod,
2668 resultReceiver));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002669 mInputShown = true;
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002670 if (mHaveConnection && !mVisibleBound) {
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002671 bindCurrentInputMethodServiceLocked(
Yohei Yukawaa67a4592017-03-30 15:57:02 -07002672 mCurIntent, mVisibleConnection, IME_VISIBLE_BIND_FLAGS);
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002673 mVisibleBound = true;
2674 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08002675 res = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002676 } else if (mHaveConnection && SystemClock.uptimeMillis()
satok59b424c2011-09-30 17:21:46 +09002677 >= (mLastBindTime+TIME_TO_RECONNECT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002678 // The client has asked to have the input method shown, but
2679 // we have been sitting here too long with a connection to the
2680 // service and no interface received, so let's disconnect/connect
2681 // to try to prod things along.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002682 EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002683 SystemClock.uptimeMillis()-mLastBindTime,1);
satok59b424c2011-09-30 17:21:46 +09002684 Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 mContext.unbindService(this);
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002686 bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002687 } else {
2688 if (DEBUG) {
2689 Slog.d(TAG, "Can't show input: connection = " + mHaveConnection + ", time = "
2690 + ((mLastBindTime+TIME_TO_RECONNECT) - SystemClock.uptimeMillis()));
2691 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002692 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002693
The Android Open Source Project4df24232009-03-05 14:34:35 -08002694 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002695 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002696
satok42c5a162011-05-26 16:46:14 +09002697 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -08002698 public boolean hideSoftInput(IInputMethodClient client, int flags,
2699 ResultReceiver resultReceiver) {
Dianne Hackborncef65ee2010-09-30 18:27:22 -07002700 int uid = Binder.getCallingUid();
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002701 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08002702 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002703 return false;
2704 }
2705 final long ident = Binder.clearCallingIdentity();
2706 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002707 if (mCurClient == null || client == null
2708 || mCurClient.client.asBinder() != client.asBinder()) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002709 // We need to check if this is the current client with
2710 // focus in the window manager, to allow this call to
2711 // be made before input is started in it.
Yohei Yukawa41f89c32018-09-19 14:30:04 -07002712 final ClientState cs = mClients.get(client.asBinder());
2713 if (cs == null) {
2714 throw new IllegalArgumentException("unknown client " + client.asBinder());
2715 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002716 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
2717 cs.selfReportedDisplayId)) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002718 if (DEBUG) {
2719 Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002720 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08002721 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002722 }
2723 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002724
Joe Onorato8a9b2202010-02-26 18:56:32 -08002725 if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
The Android Open Source Project4df24232009-03-05 14:34:35 -08002726 return hideCurrentInputLocked(flags, resultReceiver);
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002727 } finally {
2728 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002729 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730 }
2731 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002732
The Android Open Source Project4df24232009-03-05 14:34:35 -08002733 boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002734 if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
2735 && (mShowExplicitlyRequested || mShowForced)) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002736 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 -08002737 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002738 }
2739 if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002740 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 -08002741 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002742 }
Seigo Nonakaec928652015-06-10 15:31:20 +09002743
2744 // There is a chance that IMM#hideSoftInput() is called in a transient state where
2745 // IMMS#InputShown is already updated to be true whereas IMMS#mImeWindowVis is still waiting
2746 // to be updated with the new value sent from IME process. Even in such a transient state
2747 // historically we have accepted an incoming call of IMM#hideSoftInput() from the
2748 // application process as a valid request, and have even promised such a behavior with CTS
2749 // since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only
2750 // IMMS#InputShown indicates that the software keyboard is shown.
2751 // TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
2752 final boolean shouldHideSoftInput = (mCurMethod != null) && (mInputShown ||
2753 (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002754 boolean res;
Seigo Nonakaec928652015-06-10 15:31:20 +09002755 if (shouldHideSoftInput) {
2756 // The IME will report its visible state again after the following message finally
2757 // delivered to the IME process as an IPC. Hence the inconsistency between
2758 // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
2759 // the final state.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002760 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
2761 MSG_HIDE_SOFT_INPUT, mCurMethod, resultReceiver));
2762 res = true;
2763 } else {
2764 res = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002765 }
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002766 if (mHaveConnection && mVisibleBound) {
2767 mContext.unbindService(mVisibleConnection);
2768 mVisibleBound = false;
2769 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002770 mInputShown = false;
2771 mShowRequested = false;
2772 mShowExplicitlyRequested = false;
2773 mShowForced = false;
The Android Open Source Project4df24232009-03-05 14:34:35 -08002774 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002775 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002776
Yohei Yukawa2553e482017-12-15 15:47:33 -08002777 @NonNull
satok42c5a162011-05-26 16:46:14 +09002778 @Override
Yohei Yukawa05c25f82016-02-22 12:41:17 -08002779 public InputBindResult startInputOrWindowGainedFocus(
Yohei Yukawadc66e522018-10-21 10:43:14 -07002780 @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002781 @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
2782 int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
Yohei Yukawadc66e522018-10-21 10:43:14 -07002783 @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) {
Yohei Yukawa80498d52018-06-21 16:24:36 -07002784 if (windowToken == null) {
2785 Slog.e(TAG, "windowToken cannot be null.");
2786 return InputBindResult.NULL;
Yohei Yukawa05c25f82016-02-22 12:41:17 -08002787 }
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002788 final int callingUserId = UserHandle.getCallingUserId();
2789 final int userId;
Yohei Yukawa716897c2019-01-22 00:00:53 -08002790 if (attribute != null && attribute.targetInputMethodUser != null
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002791 && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
2792 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Yohei Yukawa670abea2019-01-28 00:00:50 -08002793 "Using EditorInfo.targetInputMethodUser requires INTERACT_ACROSS_USERS_FULL.");
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002794 userId = attribute.targetInputMethodUser.getIdentifier();
2795 if (!mUserManagerInternal.isUserRunning(userId)) {
2796 // There is a chance that we hit here because of race condition. Let's just return
2797 // an error code instead of crashing the caller process, which at least has
2798 // INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important process.
2799 Slog.e(TAG, "User #" + userId + " is not running.");
2800 return InputBindResult.INVALID_USER;
2801 }
2802 } else {
2803 userId = callingUserId;
2804 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002805 final InputBindResult result;
2806 synchronized (mMethodMap) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002807 final long ident = Binder.clearCallingIdentity();
2808 try {
2809 result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client,
2810 windowToken, startInputFlags, softInputMode, windowFlags, attribute,
2811 inputContext, missingMethods, unverifiedTargetSdkVersion, userId);
2812 } finally {
2813 Binder.restoreCallingIdentity(ident);
2814 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002815 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002816 if (result == null) {
2817 // This must never happen, but just in case.
2818 Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
Yohei Yukawaa468d702018-10-21 11:42:34 -07002819 + InputMethodDebug.startInputReasonToString(startInputReason)
Yohei Yukawa2553e482017-12-15 15:47:33 -08002820 + " windowFlags=#" + Integer.toHexString(windowFlags)
2821 + " editorInfo=" + attribute);
2822 return InputBindResult.NULL;
2823 }
2824 return result;
Yohei Yukawa05c25f82016-02-22 12:41:17 -08002825 }
2826
Yohei Yukawa2553e482017-12-15 15:47:33 -08002827 @NonNull
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002828 private InputBindResult startInputOrWindowGainedFocusInternalLocked(
Yohei Yukawadc66e522018-10-21 10:43:14 -07002829 @StartInputReason int startInputReason, IInputMethodClient client,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002830 @NonNull IBinder windowToken, @StartInputFlags int startInputFlags,
2831 @SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute,
2832 IInputContext inputContext, @MissingMethodFlags int missingMethods,
Yohei Yukawa4391c202019-01-28 00:49:10 -08002833 int unverifiedTargetSdkVersion, @UserIdInt int userId) {
Yohei Yukawa67464522019-01-28 00:50:09 -08002834 if (DEBUG) {
2835 Slog.v(TAG, "startInputOrWindowGainedFocusInternalLocked: reason="
2836 + InputMethodDebug.startInputReasonToString(startInputReason)
2837 + " client=" + client.asBinder()
2838 + " inputContext=" + inputContext
2839 + " missingMethods="
2840 + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
2841 + " attribute=" + attribute
2842 + " startInputFlags="
2843 + InputMethodDebug.startInputFlagsToString(startInputFlags)
2844 + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode)
2845 + " windowFlags=#" + Integer.toHexString(windowFlags)
2846 + " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion);
2847 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002848
Yohei Yukawa67464522019-01-28 00:50:09 -08002849 final int windowDisplayId = mWindowManagerInternal.getDisplayIdForWindow(windowToken);
2850
2851 final ClientState cs = mClients.get(client.asBinder());
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002852 if (cs == null) {
Yohei Yukawa67464522019-01-28 00:50:09 -08002853 throw new IllegalArgumentException("unknown client " + client.asBinder());
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002854 }
2855 if (cs.selfReportedDisplayId != windowDisplayId) {
2856 Slog.e(TAG, "startInputOrWindowGainedFocusInternal: display ID mismatch."
2857 + " from client:" + cs.selfReportedDisplayId
2858 + " from window:" + windowDisplayId);
2859 return InputBindResult.DISPLAY_ID_MISMATCH;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002860 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08002861
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002862 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
2863 cs.selfReportedDisplayId)) {
2864 // Check with the window manager to make sure this client actually
2865 // has a window with focus. If not, reject. This is thread safe
2866 // because if the focus changes some time before or after, the
2867 // next client receiving focus that has any interest in input will
2868 // be calling through here after that change happens.
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002869 if (DEBUG) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002870 Slog.w(TAG, "Focus gain on non-focused client " + cs.client
2871 + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002872 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002873 return InputBindResult.NOT_IME_TARGET_WINDOW;
2874 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002875
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002876 // cross-profile access is always allowed here to allow profile-switching.
2877 if (!mSettings.isCurrentProfile(userId)) {
2878 Slog.w(TAG, "A background user is requesting window. Hiding IME.");
2879 Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
2880 + " a background user, use EditorInfo.targetInputMethodUser with"
2881 + " INTERACT_ACROSS_USERS_FULL permission.");
2882 hideCurrentInputLocked(0, null);
2883 return InputBindResult.INVALID_USER;
2884 }
2885
2886 if (PER_PROFILE_IME_ENABLED && userId != mSettings.getCurrentUserId()) {
2887 switchUserLocked(userId);
2888 }
2889 // Master feature flag that overrides other conditions and forces IME preRendering.
2890 if (DEBUG) {
2891 Slog.v(TAG, "IME PreRendering MASTER flag: "
Yohei Yukawa67464522019-01-28 00:50:09 -08002892 + DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() + ", LowRam: " + mIsLowRam);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002893 }
2894 // pre-rendering not supported on low-ram devices.
2895 cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam;
2896
2897 if (mCurFocusedWindow == windowToken) {
2898 if (DEBUG) {
2899 Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
2900 + " attribute=" + attribute + ", token = " + windowToken);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002901 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002902 if (attribute != null) {
2903 return startInputUncheckedLocked(cs, inputContext, missingMethods,
2904 attribute, startInputFlags, startInputReason);
2905 }
2906 return new InputBindResult(
2907 InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
2908 null, null, null, -1);
2909 }
2910 mCurFocusedWindow = windowToken;
2911 mCurFocusedWindowSoftInputMode = softInputMode;
2912 mCurFocusedWindowClient = cs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002913
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002914 // Should we auto-show the IME even if the caller has not
2915 // specified what should be done with it?
2916 // We only do this automatically if the window can resize
2917 // to accommodate the IME (so what the user sees will give
2918 // them good context without input information being obscured
2919 // by the IME) or if running on a large screen where there
2920 // is more room for the target window + IME.
2921 final boolean doAutoShow =
Yohei Yukawa6e875592019-01-28 00:49:30 -08002922 (softInputMode & LayoutParams.SOFT_INPUT_MASK_ADJUST)
2923 == LayoutParams.SOFT_INPUT_ADJUST_RESIZE
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002924 || mRes.getConfiguration().isLayoutSizeAtLeast(
2925 Configuration.SCREENLAYOUT_SIZE_LARGE);
Yohei Yukawa67464522019-01-28 00:50:09 -08002926 final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002927
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002928 // We want to start input before showing the IME, but after closing
2929 // it. We want to do this after closing it to help the IME disappear
2930 // more quickly (not get stuck behind it initializing itself for the
2931 // new focused input, even if its window wants to hide the IME).
2932 boolean didStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002933
Yohei Yukawa67464522019-01-28 00:50:09 -08002934 InputBindResult res = null;
Yohei Yukawa6e875592019-01-28 00:49:30 -08002935 switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) {
2936 case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002937 if (!isTextEditor || !doAutoShow) {
Yohei Yukawa6e875592019-01-28 00:49:30 -08002938 if (LayoutParams.mayUseInputMethod(windowFlags)) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002939 // There is no focus view, and this window will
2940 // be behind any soft input window, so hide the
2941 // soft input window if it is shown.
2942 if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
2943 hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002944
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002945 // If focused display changed, we should unbind current method
2946 // to make app window in previous display relayout after Ime
2947 // window token removed.
2948 // Note that we can trust client's display ID as long as it matches
2949 // to the display ID obtained from the window.
2950 if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
2951 unbindCurrentMethodLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002952 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002953 }
Yohei Yukawa6e875592019-01-28 00:49:30 -08002954 } else if (isTextEditor && doAutoShow
2955 && (softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002956 // There is a focus view, and we are navigating forward
2957 // into the window, so show the input window for the user.
2958 // We only do this automatically if the window can resize
2959 // to accommodate the IME (so what the user sees will give
2960 // them good context without input information being obscured
2961 // by the IME) or if running on a large screen where there
2962 // is more room for the target window + IME.
2963 if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
2964 if (attribute != null) {
2965 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
2966 attribute, startInputFlags, startInputReason);
2967 didStart = true;
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002968 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002969 showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
2970 }
2971 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08002972 case LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002973 // Do nothing.
2974 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08002975 case LayoutParams.SOFT_INPUT_STATE_HIDDEN:
2976 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002977 if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002978 hideCurrentInputLocked(0, null);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002979 }
2980 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08002981 case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002982 if (DEBUG) Slog.v(TAG, "Window asks to hide input");
2983 hideCurrentInputLocked(0, null);
2984 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08002985 case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
2986 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002987 if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002988 if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
2989 unverifiedTargetSdkVersion, startInputFlags)) {
2990 if (attribute != null) {
Yohei Yukawa67464522019-01-28 00:50:09 -08002991 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
2992 attribute, startInputFlags, startInputReason);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002993 didStart = true;
2994 }
2995 showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
2996 } else {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002997 Slog.e(TAG, "SOFT_INPUT_STATE_VISIBLE is ignored because"
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002998 + " there is no focused view that also returns true from"
2999 + " View#onCheckIsTextEditor()");
3000 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003001 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003002 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003003 case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003004 if (DEBUG) Slog.v(TAG, "Window asks to always show input");
3005 if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
3006 unverifiedTargetSdkVersion, startInputFlags)) {
3007 if (attribute != null) {
3008 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3009 attribute, startInputFlags, startInputReason);
3010 didStart = true;
3011 }
3012 showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
3013 } else {
3014 Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
3015 + " there is no focused view that also returns true from"
3016 + " View#onCheckIsTextEditor()");
3017 }
3018 break;
3019 }
3020
3021 if (!didStart) {
3022 if (attribute != null) {
3023 if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
3024 || (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003025 res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003026 startInputFlags, startInputReason);
3027 } else {
3028 res = InputBindResult.NO_EDITOR;
3029 }
3030 } else {
3031 res = InputBindResult.NULL_EDITOR_INFO;
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003032 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003033 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08003034 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003035 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003036
Guliz Tuncay6908c152017-06-02 16:06:10 -07003037 private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003038 // TODO(yukawa): multi-display support.
Guliz Tuncay6908c152017-06-02 16:06:10 -07003039 final int uid = Binder.getCallingUid();
lumark0b05f9e2018-11-26 15:09:06 +08003040 if (mCurFocusedWindowClient != null && client != null
Tarandeep Singheb570612018-01-29 16:20:32 -08003041 && mCurFocusedWindowClient.client.asBinder() == client.asBinder()) {
Guliz Tuncay6908c152017-06-02 16:06:10 -07003042 return true;
3043 } else if (mCurIntent != null && InputMethodUtils.checkIfPackageBelongsToUid(
3044 mAppOpsManager,
3045 uid,
3046 mCurIntent.getComponent().getPackageName())) {
3047 return true;
Guliz Tuncay6908c152017-06-02 16:06:10 -07003048 }
Guliz Tuncay6908c152017-06-02 16:06:10 -07003049 return false;
3050 }
3051
satok42c5a162011-05-26 16:46:14 +09003052 @Override
Seigo Nonaka14e13912015-05-06 21:04:13 -07003053 public void showInputMethodPickerFromClient(
3054 IInputMethodClient client, int auxiliarySubtypeMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003055 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003056 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003057 return;
3058 }
Guliz Tuncay6908c152017-06-02 16:06:10 -07003059 if(!canShowInputMethodPickerLocked(client)) {
satok47a44912010-10-06 16:03:58 +09003060 Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
Dianne Hackborncef65ee2010-09-30 18:27:22 -07003061 + Binder.getCallingUid() + ": " + client);
Guliz Tuncay6908c152017-06-02 16:06:10 -07003062 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003063 }
3064
satok440aab52010-11-25 09:43:11 +09003065 // Always call subtype picker, because subtype picker is a superset of input method
3066 // picker.
lumark0b05f9e2018-11-26 15:09:06 +08003067 mHandler.sendMessage(mCaller.obtainMessageII(
3068 MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode,
3069 (mCurClient != null) ? mCurClient.selfReportedDisplayId : DEFAULT_DISPLAY));
satokab751aa2010-09-14 19:17:36 +09003070 }
3071 }
3072
lumark0b05f9e2018-11-26 15:09:06 +08003073 @Override
3074 public void showInputMethodPickerFromSystem(IInputMethodClient client, int auxiliarySubtypeMode,
3075 int displayId) {
3076 if (mContext.checkCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
3077 != PackageManager.PERMISSION_GRANTED) {
3078 throw new SecurityException(
3079 "showInputMethodPickerFromSystem requires WRITE_SECURE_SETTINGS permission");
3080 }
3081 // Always call subtype picker, because subtype picker is a superset of input method
3082 // picker.
3083 mHandler.sendMessage(mCaller.obtainMessageII(
3084 MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode, displayId));
3085 }
3086
Tarandeep Singheb570612018-01-29 16:20:32 -08003087 public boolean isInputMethodPickerShownForTest() {
3088 synchronized(mMethodMap) {
3089 if (mSwitchingDialog == null) {
3090 return false;
3091 }
3092 return mSwitchingDialog.isShowing();
3093 }
3094 }
3095
Yohei Yukawa0c1ebff2018-12-27 14:06:28 -08003096 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003097 private void setInputMethod(@NonNull IBinder token, String id) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003098 synchronized (mMethodMap) {
Yohei Yukawa0c1ebff2018-12-27 14:06:28 -08003099 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003100 return;
3101 }
3102 setInputMethodWithSubtypeIdLocked(token, id, NOT_A_SUBTYPE_ID);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003103 }
satok28203512010-11-24 11:06:49 +09003104 }
3105
Yohei Yukawa4773ee12018-12-24 21:13:53 -08003106 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003107 private void setInputMethodAndSubtype(@NonNull IBinder token, String id,
3108 InputMethodSubtype subtype) {
satok28203512010-11-24 11:06:49 +09003109 synchronized (mMethodMap) {
Yohei Yukawa4773ee12018-12-24 21:13:53 -08003110 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003111 return;
3112 }
satok28203512010-11-24 11:06:49 +09003113 if (subtype != null) {
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003114 setInputMethodWithSubtypeIdLocked(token, id,
3115 InputMethodUtils.getSubtypeIdFromHashCode(mMethodMap.get(id),
3116 subtype.hashCode()));
satok28203512010-11-24 11:06:49 +09003117 } else {
3118 setInputMethod(token, id);
3119 }
3120 }
satokab751aa2010-09-14 19:17:36 +09003121 }
3122
satok42c5a162011-05-26 16:46:14 +09003123 @Override
satokb416a712010-11-25 20:42:14 +09003124 public void showInputMethodAndSubtypeEnablerFromClient(
satok217f5482010-12-15 05:19:19 +09003125 IInputMethodClient client, String inputMethodId) {
satokb416a712010-11-25 20:42:14 +09003126 synchronized (mMethodMap) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003127 // TODO(yukawa): Should we verify the display ID?
Yohei Yukawa46d74762019-01-22 10:17:22 -08003128 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003129 return;
3130 }
satok7fee71f2010-12-17 18:54:26 +09003131 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
3132 MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
satokb416a712010-11-25 20:42:14 +09003133 }
3134 }
3135
Yohei Yukawa0c499082018-12-09 18:52:02 -08003136 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003137 private boolean switchToPreviousInputMethod(@NonNull IBinder token) {
satok735cf382010-11-11 20:40:09 +09003138 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003139 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa0c499082018-12-09 18:52:02 -08003140 return false;
3141 }
satokc445bcd2011-01-25 18:57:24 +09003142 final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
satok4fc87d62011-05-20 16:13:43 +09003143 final InputMethodInfo lastImi;
satok208d5632011-05-20 22:13:38 +09003144 if (lastIme != null) {
satok4fc87d62011-05-20 16:13:43 +09003145 lastImi = mMethodMap.get(lastIme.first);
3146 } else {
3147 lastImi = null;
satok735cf382010-11-11 20:40:09 +09003148 }
satok4fc87d62011-05-20 16:13:43 +09003149 String targetLastImiId = null;
3150 int subtypeId = NOT_A_SUBTYPE_ID;
3151 if (lastIme != null && lastImi != null) {
3152 final boolean imiIdIsSame = lastImi.getId().equals(mCurMethodId);
Narayan Kamatha09b4d22016-04-15 18:32:45 +01003153 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
satok4fc87d62011-05-20 16:13:43 +09003154 final int currentSubtypeHash = mCurrentSubtype == null ? NOT_A_SUBTYPE_ID
3155 : mCurrentSubtype.hashCode();
3156 // If the last IME is the same as the current IME and the last subtype is not
3157 // defined, there is no need to switch to the last IME.
3158 if (!imiIdIsSame || lastSubtypeHash != currentSubtypeHash) {
3159 targetLastImiId = lastIme.first;
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003160 subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
satok4fc87d62011-05-20 16:13:43 +09003161 }
3162 }
3163
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003164 if (TextUtils.isEmpty(targetLastImiId)
3165 && !InputMethodUtils.canAddToLastInputMethod(mCurrentSubtype)) {
satok4fc87d62011-05-20 16:13:43 +09003166 // This is a safety net. If the currentSubtype can't be added to the history
3167 // and the framework couldn't find the last ime, we will make the last ime be
3168 // the most applicable enabled keyboard subtype of the system imes.
3169 final List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
3170 if (enabled != null) {
3171 final int N = enabled.size();
3172 final String locale = mCurrentSubtype == null
3173 ? mRes.getConfiguration().locale.toString()
3174 : mCurrentSubtype.getLocale();
3175 for (int i = 0; i < N; ++i) {
3176 final InputMethodInfo imi = enabled.get(i);
Yohei Yukawafd70fe82018-04-08 12:19:56 -07003177 if (imi.getSubtypeCount() > 0 && imi.isSystem()) {
satok4fc87d62011-05-20 16:13:43 +09003178 InputMethodSubtype keyboardSubtype =
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003179 InputMethodUtils.findLastResortApplicableSubtypeLocked(mRes,
3180 InputMethodUtils.getSubtypes(imi),
3181 InputMethodUtils.SUBTYPE_MODE_KEYBOARD, locale, true);
satok4fc87d62011-05-20 16:13:43 +09003182 if (keyboardSubtype != null) {
3183 targetLastImiId = imi.getId();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003184 subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
satok4fc87d62011-05-20 16:13:43 +09003185 imi, keyboardSubtype.hashCode());
3186 if(keyboardSubtype.getLocale().equals(locale)) {
3187 break;
3188 }
3189 }
3190 }
3191 }
3192 }
3193 }
3194
3195 if (!TextUtils.isEmpty(targetLastImiId)) {
3196 if (DEBUG) {
3197 Slog.d(TAG, "Switch to: " + lastImi.getId() + ", " + lastIme.second
3198 + ", from: " + mCurMethodId + ", " + subtypeId);
3199 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003200 setInputMethodWithSubtypeIdLocked(token, targetLastImiId, subtypeId);
satok4fc87d62011-05-20 16:13:43 +09003201 return true;
3202 } else {
3203 return false;
3204 }
satok735cf382010-11-11 20:40:09 +09003205 }
3206 }
3207
Yohei Yukawa70f17e72018-12-09 18:51:38 -08003208 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003209 private boolean switchToNextInputMethod(@NonNull IBinder token, boolean onlyCurrentIme) {
satok688bd472012-02-09 20:09:17 +09003210 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003211 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawaa0755742014-06-04 20:28:18 +09003212 return false;
3213 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003214 final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
Yohei Yukawa136b6ce2018-05-02 10:55:35 -07003215 onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype);
satok688bd472012-02-09 20:09:17 +09003216 if (nextSubtype == null) {
3217 return false;
3218 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003219 setInputMethodWithSubtypeIdLocked(token, nextSubtype.mImi.getId(),
3220 nextSubtype.mSubtypeId);
satok688bd472012-02-09 20:09:17 +09003221 return true;
3222 }
3223 }
3224
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003225 @BinderThread
3226 private boolean shouldOfferSwitchingToNextInputMethod(@NonNull IBinder token) {
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09003227 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003228 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawaa0755742014-06-04 20:28:18 +09003229 return false;
3230 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003231 final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
Yohei Yukawa136b6ce2018-05-02 10:55:35 -07003232 false /* onlyCurrentIme */, mMethodMap.get(mCurMethodId), mCurrentSubtype);
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09003233 if (nextSubtype == null) {
3234 return false;
3235 }
3236 return true;
3237 }
3238 }
3239
3240 @Override
satok68f1b782011-04-11 14:26:04 +09003241 public InputMethodSubtype getLastInputMethodSubtype() {
3242 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003243 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003244 return null;
3245 }
satok68f1b782011-04-11 14:26:04 +09003246 final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
3247 // TODO: Handle the case of the last IME with no subtypes
3248 if (lastIme == null || TextUtils.isEmpty(lastIme.first)
3249 || TextUtils.isEmpty(lastIme.second)) return null;
3250 final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
3251 if (lastImi == null) return null;
3252 try {
Narayan Kamatha09b4d22016-04-15 18:32:45 +01003253 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003254 final int lastSubtypeId =
3255 InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
satok0e7d7d62011-07-05 13:28:06 +09003256 if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
3257 return null;
3258 }
3259 return lastImi.getSubtypeAt(lastSubtypeId);
satok68f1b782011-04-11 14:26:04 +09003260 } catch (NumberFormatException e) {
3261 return null;
3262 }
3263 }
3264 }
3265
satoke7c6998e2011-06-03 17:57:59 +09003266 @Override
satokee5e77c2011-09-02 18:50:15 +09003267 public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
satok91e88122011-07-18 11:11:42 +09003268 // By this IPC call, only a process which shares the same uid with the IME can add
3269 // additional input method subtypes to the IME.
Yohei Yukawa70f5c482016-01-04 19:42:36 -08003270 if (TextUtils.isEmpty(imiId) || subtypes == null) return;
Yohei Yukawab557d572018-12-29 21:26:26 -08003271 final ArrayList<InputMethodSubtype> toBeAdded = new ArrayList<>();
3272 for (InputMethodSubtype subtype : subtypes) {
3273 if (!toBeAdded.contains(subtype)) {
3274 toBeAdded.add(subtype);
3275 } else {
3276 Slog.w(TAG, "Duplicated subtype definition found: "
3277 + subtype.getLocale() + ", " + subtype.getMode());
3278 }
3279 }
satoke7c6998e2011-06-03 17:57:59 +09003280 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003281 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003282 return;
3283 }
Yohei Yukawa79247822017-01-23 15:26:15 -08003284 if (!mSystemReady) {
3285 return;
3286 }
satok91e88122011-07-18 11:11:42 +09003287 final InputMethodInfo imi = mMethodMap.get(imiId);
satokee5e77c2011-09-02 18:50:15 +09003288 if (imi == null) return;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003289 final String[] packageInfos;
3290 try {
3291 packageInfos = mIPackageManager.getPackagesForUid(Binder.getCallingUid());
3292 } catch (RemoteException e) {
3293 Slog.e(TAG, "Failed to get package infos");
3294 return;
3295 }
satok91e88122011-07-18 11:11:42 +09003296 if (packageInfos != null) {
3297 final int packageNum = packageInfos.length;
3298 for (int i = 0; i < packageNum; ++i) {
3299 if (packageInfos[i].equals(imi.getPackageName())) {
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003300 if (subtypes.length > 0) {
Yohei Yukawab557d572018-12-29 21:26:26 -08003301 mAdditionalSubtypeMap.put(imi.getId(), toBeAdded);
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003302 } else {
Yohei Yukawab557d572018-12-29 21:26:26 -08003303 mAdditionalSubtypeMap.remove(imi.getId());
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003304 }
Yohei Yukawab557d572018-12-29 21:26:26 -08003305 AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
3306 mSettings.getCurrentUserId());
satokc5933802011-08-31 21:26:04 +09003307 final long ident = Binder.clearCallingIdentity();
3308 try {
Yohei Yukawa94e33302016-02-12 19:37:03 -08003309 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
satokc5933802011-08-31 21:26:04 +09003310 } finally {
3311 Binder.restoreCallingIdentity(ident);
3312 }
satokee5e77c2011-09-02 18:50:15 +09003313 return;
satok91e88122011-07-18 11:11:42 +09003314 }
3315 }
3316 }
satoke7c6998e2011-06-03 17:57:59 +09003317 }
satokee5e77c2011-09-02 18:50:15 +09003318 return;
satoke7c6998e2011-06-03 17:57:59 +09003319 }
3320
Yohei Yukawab985e6e2018-09-05 17:07:52 -07003321 /**
3322 * This is kept due to {@link android.annotation.UnsupportedAppUsage} in
3323 * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in
3324 * {@link InputMethodService#onCreate()}.
3325 *
3326 * <p>TODO(Bug 113914148): Check if we can remove this.</p>
3327 * @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight()}
3328 */
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09003329 @Override
3330 public int getInputMethodWindowVisibleHeight() {
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003331 // TODO(yukawa): Should we verify the display ID?
lumark90120a82018-08-15 00:33:03 +08003332 return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09003333 }
3334
Yohei Yukawac54c1172018-09-06 11:39:50 -07003335 @BinderThread
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003336 private void notifyUserAction(@NonNull IBinder token) {
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003337 if (DEBUG) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003338 Slog.d(TAG, "Got the notification of a user action.");
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003339 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003340 synchronized (mMethodMap) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003341 if (mCurToken != token) {
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09003342 if (DEBUG) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003343 Slog.d(TAG, "Ignoring the user action notification from IMEs that are no longer"
3344 + " active.");
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09003345 }
3346 return;
3347 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003348 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
3349 if (imi != null) {
Yohei Yukawa02970512014-06-05 16:16:18 +09003350 mSwitchingController.onUserActionLocked(imi, mCurrentSubtype);
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003351 }
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003352 }
3353 }
3354
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003355 @BinderThread
3356 private void reportPreRendered(IBinder token, EditorInfo info) {
3357 synchronized (mMethodMap) {
3358 if (!calledWithValidTokenLocked(token)) {
3359 return;
3360 }
3361 if (mCurClient != null && mCurClient.client != null) {
3362 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
3363 MSG_REPORT_PRE_RENDERED, info, mCurClient));
3364 }
3365 }
3366 }
3367
3368 @BinderThread
3369 private void applyImeVisibility(IBinder token, boolean setVisible) {
3370 synchronized (mMethodMap) {
3371 if (!calledWithValidTokenLocked(token)) {
3372 return;
3373 }
3374 if (mCurClient != null && mCurClient.client != null) {
3375 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
3376 MSG_APPLY_IME_VISIBILITY, setVisible ? 1 : 0, mCurClient));
3377 }
3378 }
3379 }
3380
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003381 private void setInputMethodWithSubtypeIdLocked(IBinder token, String id, int subtypeId) {
3382 if (token == null) {
3383 if (mContext.checkCallingOrSelfPermission(
3384 android.Manifest.permission.WRITE_SECURE_SETTINGS)
3385 != PackageManager.PERMISSION_GRANTED) {
3386 throw new SecurityException(
3387 "Using null token requires permission "
3388 + android.Manifest.permission.WRITE_SECURE_SETTINGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003389 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003390 } else if (mCurToken != token) {
3391 Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
3392 + " token: " + token);
3393 return;
3394 }
3395
3396 final long ident = Binder.clearCallingIdentity();
3397 try {
3398 setInputMethodLocked(id, subtypeId);
3399 } finally {
3400 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003401 }
3402 }
3403
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003404 @BinderThread
3405 private void hideMySoftInput(@NonNull IBinder token, int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003406 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003407 if (!calledWithValidTokenLocked(token)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003408 return;
3409 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003410 long ident = Binder.clearCallingIdentity();
3411 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003412 hideCurrentInputLocked(flags, null);
3413 } finally {
3414 Binder.restoreCallingIdentity(ident);
3415 }
3416 }
3417 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003418
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003419 @BinderThread
3420 private void showMySoftInput(@NonNull IBinder token, int flags) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003421 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003422 if (!calledWithValidTokenLocked(token)) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003423 return;
3424 }
3425 long ident = Binder.clearCallingIdentity();
3426 try {
3427 showCurrentInputLocked(flags, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003428 } finally {
3429 Binder.restoreCallingIdentity(ident);
3430 }
3431 }
3432 }
3433
3434 void setEnabledSessionInMainThread(SessionState session) {
3435 if (mEnabledSession != session) {
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003436 if (mEnabledSession != null && mEnabledSession.session != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003437 try {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003438 if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003439 mEnabledSession.method.setSessionEnabled(mEnabledSession.session, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003440 } catch (RemoteException e) {
3441 }
3442 }
3443 mEnabledSession = session;
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003444 if (mEnabledSession != null && mEnabledSession.session != null) {
3445 try {
3446 if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
3447 mEnabledSession.method.setSessionEnabled(mEnabledSession.session, true);
3448 } catch (RemoteException e) {
3449 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003450 }
3451 }
3452 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003453
Yohei Yukawa930328c2017-10-18 20:19:53 -07003454 @MainThread
satok42c5a162011-05-26 16:46:14 +09003455 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003456 public boolean handleMessage(Message msg) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003457 SomeArgs args;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003458 switch (msg.what) {
satokab751aa2010-09-14 19:17:36 +09003459 case MSG_SHOW_IM_SUBTYPE_PICKER:
Seigo Nonaka14e13912015-05-06 21:04:13 -07003460 final boolean showAuxSubtypes;
lumark0b05f9e2018-11-26 15:09:06 +08003461 final int displayId = msg.arg2;
Seigo Nonaka14e13912015-05-06 21:04:13 -07003462 switch (msg.arg1) {
3463 case InputMethodManager.SHOW_IM_PICKER_MODE_AUTO:
3464 // This is undocumented so far, but IMM#showInputMethodPicker() has been
3465 // implemented so that auxiliary subtypes will be excluded when the soft
3466 // keyboard is invisible.
3467 showAuxSubtypes = mInputShown;
3468 break;
3469 case InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES:
3470 showAuxSubtypes = true;
3471 break;
3472 case InputMethodManager.SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES:
3473 showAuxSubtypes = false;
3474 break;
3475 default:
3476 Slog.e(TAG, "Unknown subtype picker mode = " + msg.arg1);
3477 return false;
3478 }
lumark0b05f9e2018-11-26 15:09:06 +08003479 showInputMethodMenu(showAuxSubtypes, displayId);
satokab751aa2010-09-14 19:17:36 +09003480 return true;
3481
satok47a44912010-10-06 16:03:58 +09003482 case MSG_SHOW_IM_SUBTYPE_ENABLER:
Yohei Yukawa41f34272015-12-14 15:41:52 -08003483 showInputMethodAndSubtypeEnabler((String)msg.obj);
satok217f5482010-12-15 05:19:19 +09003484 return true;
3485
3486 case MSG_SHOW_IM_CONFIG:
3487 showConfigureInputMethods();
satok47a44912010-10-06 16:03:58 +09003488 return true;
3489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003490 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003491
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003492 case MSG_UNBIND_INPUT:
3493 try {
3494 ((IInputMethod)msg.obj).unbindInput();
3495 } catch (RemoteException e) {
3496 // There is nothing interesting about the method dying.
3497 }
3498 return true;
3499 case MSG_BIND_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003500 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003501 try {
3502 ((IInputMethod)args.arg1).bindInput((InputBinding)args.arg2);
3503 } catch (RemoteException e) {
3504 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003505 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 return true;
3507 case MSG_SHOW_SOFT_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003508 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003509 try {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003510 if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput("
Craig Mautner6efb4c72013-03-13 10:17:41 -07003511 + msg.arg1 + ", " + args.arg2 + ")");
Craig Mautnerca0ac712013-03-14 09:43:02 -07003512 ((IInputMethod)args.arg1).showSoftInput(msg.arg1, (ResultReceiver)args.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003513 } catch (RemoteException e) {
3514 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003515 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 return true;
3517 case MSG_HIDE_SOFT_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003518 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003519 try {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003520 if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, "
Craig Mautner6efb4c72013-03-13 10:17:41 -07003521 + args.arg2 + ")");
Craig Mautnerca0ac712013-03-14 09:43:02 -07003522 ((IInputMethod)args.arg1).hideSoftInput(0, (ResultReceiver)args.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003523 } catch (RemoteException e) {
3524 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003525 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003526 return true;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07003527 case MSG_HIDE_CURRENT_INPUT_METHOD:
3528 synchronized (mMethodMap) {
3529 hideCurrentInputLocked(0, null);
3530 }
3531 return true;
Yohei Yukawac54c1172018-09-06 11:39:50 -07003532 case MSG_INITIALIZE_IME:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003533 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003534 try {
lumark90120a82018-08-15 00:33:03 +08003535 if (DEBUG) {
3536 Slog.v(TAG, "Sending attach of token: " + args.arg2 + " for display: "
3537 + msg.arg1);
3538 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07003539 final IBinder token = (IBinder) args.arg2;
lumark90120a82018-08-15 00:33:03 +08003540 ((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
Yohei Yukawac54c1172018-09-06 11:39:50 -07003541 new InputMethodPrivilegedOperationsImpl(this, token));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003542 } catch (RemoteException e) {
3543 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003544 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003545 return true;
Jeff Brownc28867a2013-03-26 15:42:39 -07003546 case MSG_CREATE_SESSION: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003547 args = (SomeArgs)msg.obj;
Jeff Brown1951ce82013-04-04 22:45:12 -07003548 IInputMethod method = (IInputMethod)args.arg1;
Jeff Brownc28867a2013-03-26 15:42:39 -07003549 InputChannel channel = (InputChannel)args.arg2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003550 try {
Jeff Brown1951ce82013-04-04 22:45:12 -07003551 method.createSession(channel, (IInputSessionCallback)args.arg3);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003552 } catch (RemoteException e) {
Jeff Brownc28867a2013-03-26 15:42:39 -07003553 } finally {
Jeff Brown1951ce82013-04-04 22:45:12 -07003554 // Dispose the channel if the input method is not local to this process
3555 // because the remote proxy will get its own copy when unparceled.
3556 if (channel != null && Binder.isProxy(method)) {
Jeff Brownc28867a2013-03-26 15:42:39 -07003557 channel.dispose();
3558 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003559 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003560 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003561 return true;
Jeff Brownc28867a2013-03-26 15:42:39 -07003562 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003563 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003564
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003565 case MSG_START_INPUT: {
Yohei Yukawaf7526b52017-02-11 20:57:10 -08003566 final int missingMethods = msg.arg1;
3567 final boolean restarting = msg.arg2 != 0;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003568 args = (SomeArgs) msg.obj;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08003569 final IBinder startInputToken = (IBinder) args.arg1;
3570 final SessionState session = (SessionState) args.arg2;
3571 final IInputContext inputContext = (IInputContext) args.arg3;
3572 final EditorInfo editorInfo = (EditorInfo) args.arg4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003573 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003574 setEnabledSessionInMainThread(session);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08003575 session.method.startInput(startInputToken, inputContext, missingMethods,
Tarandeep Singheadb1392018-11-09 18:15:57 +01003576 editorInfo, restarting, session.client.shouldPreRenderIme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003577 } catch (RemoteException e) {
3578 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003579 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003580 return true;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003581 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003582
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003583 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003584
Yohei Yukawa33e81792015-11-17 21:14:42 -08003585 case MSG_UNBIND_CLIENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003586 try {
Yohei Yukawa33e81792015-11-17 21:14:42 -08003587 ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003588 } catch (RemoteException e) {
3589 // There is nothing interesting about the last client dying.
3590 }
3591 return true;
Yohei Yukawa33e81792015-11-17 21:14:42 -08003592 case MSG_BIND_CLIENT: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003593 args = (SomeArgs)msg.obj;
Jeff Brown1951ce82013-04-04 22:45:12 -07003594 IInputMethodClient client = (IInputMethodClient)args.arg1;
3595 InputBindResult res = (InputBindResult)args.arg2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003596 try {
Jeff Brown1951ce82013-04-04 22:45:12 -07003597 client.onBindMethod(res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003598 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003599 Slog.w(TAG, "Client died receiving input method " + args.arg2);
Jeff Brown1951ce82013-04-04 22:45:12 -07003600 } finally {
3601 // Dispose the channel if the input method is not local to this process
3602 // because the remote proxy will get its own copy when unparceled.
3603 if (res.channel != null && Binder.isProxy(client)) {
3604 res.channel.dispose();
3605 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003606 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003607 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003608 return true;
Jeff Brown1951ce82013-04-04 22:45:12 -07003609 }
Dianne Hackborna6e41342012-05-22 16:30:34 -07003610 case MSG_SET_ACTIVE:
3611 try {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003612 ((ClientState)msg.obj).client.setActive(msg.arg1 != 0, msg.arg2 != 0);
Dianne Hackborna6e41342012-05-22 16:30:34 -07003613 } catch (RemoteException e) {
3614 Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
3615 + ((ClientState)msg.obj).pid + " uid "
3616 + ((ClientState)msg.obj).uid);
3617 }
3618 return true;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003619 case MSG_SET_INTERACTIVE:
3620 handleSetInteractive(msg.arg1 != 0);
3621 return true;
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003622 case MSG_REPORT_FULLSCREEN_MODE: {
3623 final boolean fullscreen = msg.arg1 != 0;
3624 final ClientState clientState = (ClientState)msg.obj;
3625 try {
3626 clientState.client.reportFullscreenMode(fullscreen);
3627 } catch (RemoteException e) {
3628 Slog.w(TAG, "Got RemoteException sending "
3629 + "reportFullscreen(" + fullscreen + ") notification to pid="
3630 + clientState.pid + " uid=" + clientState.uid);
3631 }
3632 return true;
3633 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003634 case MSG_REPORT_PRE_RENDERED: {
3635 args = (SomeArgs) msg.obj;
3636 final EditorInfo info = (EditorInfo) args.arg1;
3637 final ClientState clientState = (ClientState) args.arg2;
3638 try {
3639 clientState.client.reportPreRendered(info);
3640 } catch (RemoteException e) {
3641 Slog.w(TAG, "Got RemoteException sending "
3642 + "reportPreRendered(" + info + ") notification to pid="
3643 + clientState.pid + " uid=" + clientState.uid);
3644 }
3645 args.recycle();
3646 return true;
3647 }
3648 case MSG_APPLY_IME_VISIBILITY: {
3649 final boolean setVisible = msg.arg1 != 0;
3650 final ClientState clientState = (ClientState) msg.obj;
3651 try {
3652 clientState.client.applyImeVisibility(setVisible);
3653 } catch (RemoteException e) {
3654 Slog.w(TAG, "Got RemoteException sending "
3655 + "applyImeVisibility(" + setVisible + ") notification to pid="
3656 + clientState.pid + " uid=" + clientState.uid);
3657 }
3658 return true;
3659 }
satok01038492012-04-09 21:08:27 +09003660
3661 // --------------------------------------------------------------
3662 case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
Michael Wright7b5a96b2014-08-09 19:28:42 -07003663 mHardKeyboardListener.handleHardKeyboardStatusChange(msg.arg1 == 1);
satok01038492012-04-09 21:08:27 +09003664 return true;
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07003665 case MSG_SYSTEM_UNLOCK_USER:
3666 final int userId = msg.arg1;
3667 onUnlockUser(userId);
3668 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003669 }
3670 return false;
3671 }
3672
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003673 private void handleSetInteractive(final boolean interactive) {
3674 synchronized (mMethodMap) {
3675 mIsInteractive = interactive;
Yohei Yukawa849443c2019-01-21 09:02:25 -08003676 updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003677
3678 // Inform the current client of the change in active status
3679 if (mCurClient != null && mCurClient.client != null) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003680 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
3681 MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mInFullscreenMode ? 1 : 0,
3682 mCurClient));
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003683 }
3684 }
3685 }
3686
satokdc9ddae2011-10-06 12:22:36 +09003687 private boolean chooseNewDefaultIMELocked() {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003688 final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
3689 mSettings.getEnabledInputMethodListLocked());
satokdc9ddae2011-10-06 12:22:36 +09003690 if (imi != null) {
satok03eb319a2010-11-11 18:17:42 +09003691 if (DEBUG) {
3692 Slog.d(TAG, "New default IME was selected: " + imi.getId());
3693 }
satok723a27e2010-11-11 14:58:11 +09003694 resetSelectedInputMethodAndSubtypeLocked(imi.getId());
Brandon Ballinger6da35a02009-10-21 00:38:13 -07003695 return true;
3696 }
3697
3698 return false;
3699 }
3700
Yohei Yukawa05139322018-12-25 10:34:14 -08003701 static void queryInputMethodServicesInternal(Context context,
3702 @UserIdInt int userId, ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap,
3703 ArrayMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList) {
3704 methodList.clear();
3705 methodMap.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003706
Yohei Yukawaed4952a2016-02-17 07:57:25 -08003707 // Note: We do not specify PackageManager.MATCH_ENCRYPTION_* flags here because the default
3708 // behavior of PackageManager is exactly what we want. It by default picks up appropriate
3709 // services depending on the unlock state for the specified user.
Yohei Yukawa05139322018-12-25 10:34:14 -08003710 final List<ResolveInfo> services = context.getPackageManager().queryIntentServicesAsUser(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003711 new Intent(InputMethod.SERVICE_INTERFACE),
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08003712 PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS,
Yohei Yukawa05139322018-12-25 10:34:14 -08003713 userId);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003714
Yohei Yukawa05139322018-12-25 10:34:14 -08003715 methodList.ensureCapacity(services.size());
3716 methodMap.ensureCapacity(services.size());
3717
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003718 for (int i = 0; i < services.size(); ++i) {
3719 ResolveInfo ri = services.get(i);
3720 ServiceInfo si = ri.serviceInfo;
Yohei Yukawaddad4b92017-02-02 01:46:13 -08003721 final String imeId = InputMethodInfo.computeId(ri);
3722 if (!android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
3723 Slog.w(TAG, "Skipping input method " + imeId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003724 + ": it does not require the permission "
3725 + android.Manifest.permission.BIND_INPUT_METHOD);
3726 continue;
3727 }
3728
Yohei Yukawaddad4b92017-02-02 01:46:13 -08003729 if (DEBUG) Slog.d(TAG, "Checking " + imeId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003730
3731 try {
Yohei Yukawa05139322018-12-25 10:34:14 -08003732 final InputMethodInfo imi = new InputMethodInfo(context, ri,
3733 additionalSubtypeMap.get(imeId));
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08003734 if (imi.isVrOnly()) {
3735 continue; // Skip VR-only IME, which isn't supported for now.
3736 }
Yohei Yukawa05139322018-12-25 10:34:14 -08003737 methodList.add(imi);
3738 methodMap.put(imi.getId(), imi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003739 if (DEBUG) {
Yohei Yukawa05139322018-12-25 10:34:14 -08003740 Slog.d(TAG, "Found an input method " + imi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003741 }
Tadashi G. Takaoka3c23d5b2016-09-16 11:41:07 +09003742 } catch (Exception e) {
Yohei Yukawaddad4b92017-02-02 01:46:13 -08003743 Slog.wtf(TAG, "Unable to load input method " + imeId, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003744 }
3745 }
Yohei Yukawa05139322018-12-25 10:34:14 -08003746 }
3747
3748 @GuardedBy("mMethodMap")
3749 void buildInputMethodListLocked(boolean resetDefaultEnabledIme) {
3750 if (DEBUG) {
3751 Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
3752 + " \n ------ caller=" + Debug.getCallers(10));
3753 }
3754 if (!mSystemReady) {
3755 Slog.e(TAG, "buildInputMethodListLocked is not allowed until system is ready");
3756 return;
3757 }
3758 mMethodMapUpdateCount++;
3759 mMyPackageMonitor.clearKnownImePackageNamesLocked();
3760
3761 queryInputMethodServicesInternal(mContext, mSettings.getCurrentUserId(),
Yohei Yukawab557d572018-12-29 21:26:26 -08003762 mAdditionalSubtypeMap, mMethodMap, mMethodList);
Brandon Ballinger6da35a02009-10-21 00:38:13 -07003763
Yohei Yukawac4e44912017-02-09 19:30:22 -08003764 // Construct the set of possible IME packages for onPackageChanged() to avoid false
3765 // negatives when the package state remains to be the same but only the component state is
3766 // changed.
3767 {
3768 // Here we intentionally use PackageManager.MATCH_DISABLED_COMPONENTS since the purpose
3769 // of this query is to avoid false negatives. PackageManager.MATCH_ALL could be more
3770 // conservative, but it seems we cannot use it for now (Issue 35176630).
Yohei Yukawa05139322018-12-25 10:34:14 -08003771 final List<ResolveInfo> allInputMethodServices =
3772 mContext.getPackageManager().queryIntentServicesAsUser(
3773 new Intent(InputMethod.SERVICE_INTERFACE),
3774 PackageManager.MATCH_DISABLED_COMPONENTS, mSettings.getCurrentUserId());
Yohei Yukawac4e44912017-02-09 19:30:22 -08003775 final int N = allInputMethodServices.size();
3776 for (int i = 0; i < N; ++i) {
3777 final ServiceInfo si = allInputMethodServices.get(i).serviceInfo;
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08003778 if (android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
3779 mMyPackageMonitor.addKnownImePackageNameLocked(si.packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08003780 }
Yohei Yukawac4e44912017-02-09 19:30:22 -08003781 }
3782 }
3783
Yohei Yukawa9c372192018-03-20 22:54:56 -07003784 boolean reenableMinimumNonAuxSystemImes = false;
Yohei Yukawa859df052016-02-17 07:56:46 -08003785 // TODO: The following code should find better place to live.
3786 if (!resetDefaultEnabledIme) {
3787 boolean enabledImeFound = false;
Yohei Yukawa9c372192018-03-20 22:54:56 -07003788 boolean enabledNonAuxImeFound = false;
Yohei Yukawa859df052016-02-17 07:56:46 -08003789 final List<InputMethodInfo> enabledImes = mSettings.getEnabledInputMethodListLocked();
3790 final int N = enabledImes.size();
3791 for (int i = 0; i < N; ++i) {
3792 final InputMethodInfo imi = enabledImes.get(i);
3793 if (mMethodList.contains(imi)) {
3794 enabledImeFound = true;
Yohei Yukawa9c372192018-03-20 22:54:56 -07003795 if (!imi.isAuxiliaryIme()) {
3796 enabledNonAuxImeFound = true;
3797 break;
3798 }
Yohei Yukawa859df052016-02-17 07:56:46 -08003799 }
3800 }
3801 if (!enabledImeFound) {
Yohei Yukawad0332832017-02-01 13:59:43 -08003802 if (DEBUG) {
3803 Slog.i(TAG, "All the enabled IMEs are gone. Reset default enabled IMEs.");
3804 }
Yohei Yukawa859df052016-02-17 07:56:46 -08003805 resetDefaultEnabledIme = true;
3806 resetSelectedInputMethodAndSubtypeLocked("");
Yohei Yukawa9c372192018-03-20 22:54:56 -07003807 } else if (!enabledNonAuxImeFound) {
3808 if (DEBUG) {
3809 Slog.i(TAG, "All the enabled non-Aux IMEs are gone. Do partial reset.");
3810 }
3811 reenableMinimumNonAuxSystemImes = true;
Yohei Yukawa859df052016-02-17 07:56:46 -08003812 }
3813 }
3814
Yohei Yukawa9c372192018-03-20 22:54:56 -07003815 if (resetDefaultEnabledIme || reenableMinimumNonAuxSystemImes) {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09003816 final ArrayList<InputMethodInfo> defaultEnabledIme =
Yohei Yukawa9c372192018-03-20 22:54:56 -07003817 InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList,
3818 reenableMinimumNonAuxSystemImes);
Yohei Yukawa68645a62016-02-17 07:54:20 -08003819 final int N = defaultEnabledIme.size();
3820 for (int i = 0; i < N; ++i) {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09003821 final InputMethodInfo imi = defaultEnabledIme.get(i);
3822 if (DEBUG) {
3823 Slog.d(TAG, "--- enable ime = " + imi);
3824 }
3825 setInputMethodEnabledLocked(imi.getId(), true);
3826 }
3827 }
3828
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003829 final String defaultImiId = mSettings.getSelectedInputMethod();
satok0a1bcf42012-05-16 19:26:31 +09003830 if (!TextUtils.isEmpty(defaultImiId)) {
Yohei Yukawa94e33302016-02-12 19:37:03 -08003831 if (!mMethodMap.containsKey(defaultImiId)) {
satok0a1bcf42012-05-16 19:26:31 +09003832 Slog.w(TAG, "Default IME is uninstalled. Choose new default IME.");
3833 if (chooseNewDefaultIMELocked()) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07003834 updateInputMethodsFromSettingsLocked(true);
satok0a1bcf42012-05-16 19:26:31 +09003835 }
3836 } else {
3837 // Double check that the default IME is certainly enabled.
3838 setInputMethodEnabledLocked(defaultImiId, true);
Brandon Ballinger6da35a02009-10-21 00:38:13 -07003839 }
3840 }
Yohei Yukawa3d46bab2014-05-30 18:10:18 +09003841 // Here is not the perfect place to reset the switching controller. Ideally
3842 // mSwitchingController and mSettings should be able to share the same state.
3843 // TODO: Make sure that mSwitchingController and mSettings are sharing the
3844 // the same enabled IMEs list.
Yohei Yukawac834a252014-05-21 22:42:32 +09003845 mSwitchingController.resetCircularListLocked(mContext);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003846 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003848 // ----------------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003849
satok217f5482010-12-15 05:19:19 +09003850 private void showInputMethodAndSubtypeEnabler(String inputMethodId) {
Tadashi G. Takaokaf49688f2011-01-20 17:56:13 +09003851 Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
satok47a44912010-10-06 16:03:58 +09003852 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
satok86417ea2010-10-27 14:11:03 +09003853 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
3854 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
satok7fee71f2010-12-17 18:54:26 +09003855 if (!TextUtils.isEmpty(inputMethodId)) {
Tadashi G. Takaoka25480202011-01-20 23:13:02 +09003856 intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
satok7fee71f2010-12-17 18:54:26 +09003857 }
Yohei Yukawa41f34272015-12-14 15:41:52 -08003858 final int userId;
3859 synchronized (mMethodMap) {
3860 userId = mSettings.getCurrentUserId();
3861 }
3862 mContext.startActivityAsUser(intent, null, UserHandle.of(userId));
satok217f5482010-12-15 05:19:19 +09003863 }
3864
3865 private void showConfigureInputMethods() {
3866 Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
3867 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
3868 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
3869 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Satoshi Kataoka3ba439d2012-10-05 18:30:13 +09003870 mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
satok47a44912010-10-06 16:03:58 +09003871 }
3872
satok2c93efc2012-04-02 19:33:47 +09003873 private boolean isScreenLocked() {
3874 return mKeyguardManager != null
3875 && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure();
3876 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003877
lumark0b05f9e2018-11-26 15:09:06 +08003878 private void showInputMethodMenu(boolean showAuxSubtypes, int displayId) {
Seigo Nonaka14e13912015-05-06 21:04:13 -07003879 if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003880
satok2c93efc2012-04-02 19:33:47 +09003881 final boolean isScreenLocked = isScreenLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003882
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003883 final String lastInputMethodId = mSettings.getSelectedInputMethod();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003884 int lastInputMethodSubtypeId = mSettings.getSelectedInputMethodSubtypeId(lastInputMethodId);
Joe Onorato8a9b2202010-02-26 18:56:32 -08003885 if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003886
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07003887 synchronized (mMethodMap) {
Yohei Yukawacf3bbff2018-11-20 17:24:20 -08003888 final List<ImeSubtypeListItem> imList =
3889 mSwitchingController.getSortedInputMethodAndSubtypeListLocked(
3890 showAuxSubtypes, isScreenLocked);
3891 if (imList.isEmpty()) {
satok7f35c8c2010-10-07 21:13:11 +09003892 return;
3893 }
3894
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07003895 hideInputMethodMenuLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003896
satokc3690562012-01-10 20:14:43 +09003897 if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003898 final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtypeLocked();
satokc3690562012-01-10 20:14:43 +09003899 if (currentSubtype != null) {
3900 final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003901 lastInputMethodSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
3902 currentImi, currentSubtype.hashCode());
satokc3690562012-01-10 20:14:43 +09003903 }
3904 }
3905
Ken Wakasa761eb372011-03-04 19:06:18 +09003906 final int N = imList.size();
satokab751aa2010-09-14 19:17:36 +09003907 mIms = new InputMethodInfo[N];
3908 mSubtypeIds = new int[N];
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07003909 int checkedItem = 0;
3910 for (int i = 0; i < N; ++i) {
Ken Wakasa05dbb652011-08-22 15:22:43 +09003911 final ImeSubtypeListItem item = imList.get(i);
3912 mIms[i] = item.mImi;
3913 mSubtypeIds[i] = item.mSubtypeId;
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07003914 if (mIms[i].getId().equals(lastInputMethodId)) {
satokab751aa2010-09-14 19:17:36 +09003915 int subtypeId = mSubtypeIds[i];
3916 if ((subtypeId == NOT_A_SUBTYPE_ID)
3917 || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0)
3918 || (subtypeId == lastInputMethodSubtypeId)) {
3919 checkedItem = i;
3920 }
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07003921 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003922 }
Alan Viverette505e3ab2014-11-24 15:22:11 -08003923
lumark0b05f9e2018-11-26 15:09:06 +08003924 final ActivityThread currentThread = ActivityThread.currentActivityThread();
Andrew Sapperstein8a3b4cb2017-04-28 14:35:31 -07003925 final Context settingsContext = new ContextThemeWrapper(
lumark0b05f9e2018-11-26 15:09:06 +08003926 displayId == DEFAULT_DISPLAY ? currentThread.getSystemUiContext()
3927 : currentThread.createSystemUiContext(displayId),
Alan Viverette505e3ab2014-11-24 15:22:11 -08003928 com.android.internal.R.style.Theme_DeviceDefault_Settings);
3929
3930 mDialogBuilder = new AlertDialog.Builder(settingsContext);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003931 mDialogBuilder.setOnCancelListener(new OnCancelListener() {
3932 @Override
3933 public void onCancel(DialogInterface dialog) {
3934 hideInputMethodMenu();
3935 }
3936 });
Alan Viverette505e3ab2014-11-24 15:22:11 -08003937
3938 final Context dialogContext = mDialogBuilder.getContext();
3939 final TypedArray a = dialogContext.obtainStyledAttributes(null,
3940 com.android.internal.R.styleable.DialogPreference,
3941 com.android.internal.R.attr.alertDialogStyle, 0);
3942 final Drawable dialogIcon = a.getDrawable(
3943 com.android.internal.R.styleable.DialogPreference_dialogIcon);
3944 a.recycle();
3945
3946 mDialogBuilder.setIcon(dialogIcon);
3947
Yohei Yukawad34e1482016-02-11 08:03:52 -08003948 final LayoutInflater inflater = dialogContext.getSystemService(LayoutInflater.class);
satok01038492012-04-09 21:08:27 +09003949 final View tv = inflater.inflate(
3950 com.android.internal.R.layout.input_method_switch_dialog_title, null);
3951 mDialogBuilder.setCustomTitle(tv);
3952
3953 // Setup layout for a toggle switch of the hardware keyboard
3954 mSwitchingDialogTitleView = tv;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003955 mSwitchingDialogTitleView
3956 .findViewById(com.android.internal.R.id.hard_keyboard_section)
Seigo Nonaka7309b122015-08-17 18:34:13 -07003957 .setVisibility(mWindowManagerInternal.isHardKeyboardAvailable()
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003958 ? View.VISIBLE : View.GONE);
Alan Viverette505e3ab2014-11-24 15:22:11 -08003959 final Switch hardKeySwitch = (Switch) mSwitchingDialogTitleView.findViewById(
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003960 com.android.internal.R.id.hard_keyboard_switch);
Michael Wright7b5a96b2014-08-09 19:28:42 -07003961 hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003962 hardKeySwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
3963 @Override
3964 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07003965 mSettings.setShowImeWithHardKeyboard(isChecked);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003966 // Ensure that the input method dialog is dismissed when changing
3967 // the hardware keyboard state.
3968 hideInputMethodMenu();
3969 }
3970 });
3971
Alan Viverette505e3ab2014-11-24 15:22:11 -08003972 final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(dialogContext,
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003973 com.android.internal.R.layout.input_method_switch_item, imList, checkedItem);
3974 final OnClickListener choiceListener = new OnClickListener() {
3975 @Override
3976 public void onClick(final DialogInterface dialog, final int which) {
3977 synchronized (mMethodMap) {
3978 if (mIms == null || mIms.length <= which || mSubtypeIds == null
3979 || mSubtypeIds.length <= which) {
3980 return;
satok01038492012-04-09 21:08:27 +09003981 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003982 final InputMethodInfo im = mIms[which];
3983 int subtypeId = mSubtypeIds[which];
3984 adapter.mCheckedItem = which;
3985 adapter.notifyDataSetChanged();
3986 hideInputMethodMenu();
3987 if (im != null) {
3988 if (subtypeId < 0 || subtypeId >= im.getSubtypeCount()) {
3989 subtypeId = NOT_A_SUBTYPE_ID;
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08003990 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003991 setInputMethodLocked(im.getId(), subtypeId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003992 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09003993 }
3994 }
3995 };
3996 mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003998 mSwitchingDialog = mDialogBuilder.create();
Dianne Hackborne3a7f622011-03-03 21:48:24 -08003999 mSwitchingDialog.setCanceledOnTouchOutside(true);
Wale Ogunwale3a931692016-11-02 16:49:48 -07004000 final Window w = mSwitchingDialog.getWindow();
Yohei Yukawa6e875592019-01-28 00:49:30 -08004001 final LayoutParams attrs = w.getAttributes();
4002 w.setType(LayoutParams.TYPE_INPUT_METHOD_DIALOG);
Wale Ogunwale3a931692016-11-02 16:49:48 -07004003 // Use an alternate token for the dialog for that window manager can group the token
4004 // with other IME windows based on type vs. grouping based on whichever token happens
4005 // to get selected by the system later on.
4006 attrs.token = mSwitchingDialogToken;
Yohei Yukawa6e875592019-01-28 00:49:30 -08004007 attrs.privateFlags |= LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
Wale Ogunwale3a931692016-11-02 16:49:48 -07004008 attrs.setTitle("Select input method");
4009 w.setAttributes(attrs);
Yohei Yukawa849443c2019-01-21 09:02:25 -08004010 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004011 mSwitchingDialog.show();
4012 }
4013 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004014
Ken Wakasa05dbb652011-08-22 15:22:43 +09004015 private static class ImeSubtypeListAdapter extends ArrayAdapter<ImeSubtypeListItem> {
4016 private final LayoutInflater mInflater;
4017 private final int mTextViewResourceId;
4018 private final List<ImeSubtypeListItem> mItemsList;
Satoshi Kataokad2142962012-11-12 18:43:06 +09004019 public int mCheckedItem;
Ken Wakasa05dbb652011-08-22 15:22:43 +09004020 public ImeSubtypeListAdapter(Context context, int textViewResourceId,
4021 List<ImeSubtypeListItem> itemsList, int checkedItem) {
4022 super(context, textViewResourceId, itemsList);
Alan Viverette505e3ab2014-11-24 15:22:11 -08004023
Ken Wakasa05dbb652011-08-22 15:22:43 +09004024 mTextViewResourceId = textViewResourceId;
4025 mItemsList = itemsList;
4026 mCheckedItem = checkedItem;
Yohei Yukawad34e1482016-02-11 08:03:52 -08004027 mInflater = context.getSystemService(LayoutInflater.class);
Ken Wakasa05dbb652011-08-22 15:22:43 +09004028 }
4029
4030 @Override
4031 public View getView(int position, View convertView, ViewGroup parent) {
4032 final View view = convertView != null ? convertView
4033 : mInflater.inflate(mTextViewResourceId, null);
4034 if (position < 0 || position >= mItemsList.size()) return view;
4035 final ImeSubtypeListItem item = mItemsList.get(position);
4036 final CharSequence imeName = item.mImeName;
4037 final CharSequence subtypeName = item.mSubtypeName;
4038 final TextView firstTextView = (TextView)view.findViewById(android.R.id.text1);
4039 final TextView secondTextView = (TextView)view.findViewById(android.R.id.text2);
4040 if (TextUtils.isEmpty(subtypeName)) {
4041 firstTextView.setText(imeName);
4042 secondTextView.setVisibility(View.GONE);
4043 } else {
4044 firstTextView.setText(subtypeName);
4045 secondTextView.setText(imeName);
4046 secondTextView.setVisibility(View.VISIBLE);
4047 }
4048 final RadioButton radioButton =
4049 (RadioButton)view.findViewById(com.android.internal.R.id.radio);
4050 radioButton.setChecked(position == mCheckedItem);
4051 return view;
4052 }
4053 }
4054
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004055 void hideInputMethodMenu() {
The Android Open Source Project10592532009-03-18 17:39:46 -07004056 synchronized (mMethodMap) {
4057 hideInputMethodMenuLocked();
4058 }
4059 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004060
The Android Open Source Project10592532009-03-18 17:39:46 -07004061 void hideInputMethodMenuLocked() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08004062 if (DEBUG) Slog.v(TAG, "Hide switching menu");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004063
The Android Open Source Project10592532009-03-18 17:39:46 -07004064 if (mSwitchingDialog != null) {
4065 mSwitchingDialog.dismiss();
4066 mSwitchingDialog = null;
Yohei Yukawa1fc7a1d2018-04-18 17:31:27 -07004067 mSwitchingDialogTitleView = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004068 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004069
Yohei Yukawa849443c2019-01-21 09:02:25 -08004070 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Project10592532009-03-18 17:39:46 -07004071 mDialogBuilder = null;
The Android Open Source Project10592532009-03-18 17:39:46 -07004072 mIms = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004073 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004074
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004075 // ----------------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004076
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004077 boolean setInputMethodEnabledLocked(String id, boolean enabled) {
4078 // Make sure this is a valid input method.
4079 InputMethodInfo imm = mMethodMap.get(id);
4080 if (imm == null) {
satokd87c2592010-09-29 11:52:06 +09004081 throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004082 }
4083
satokd87c2592010-09-29 11:52:06 +09004084 List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
4085 .getEnabledInputMethodsAndSubtypeListLocked();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004086
satokd87c2592010-09-29 11:52:06 +09004087 if (enabled) {
4088 for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
4089 if (pair.first.equals(id)) {
4090 // We are enabling this input method, but it is already enabled.
4091 // Nothing to do. The previous state was enabled.
4092 return true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004093 }
4094 }
satokd87c2592010-09-29 11:52:06 +09004095 mSettings.appendAndPutEnabledInputMethodLocked(id, false);
4096 // Previous state was disabled.
4097 return false;
4098 } else {
4099 StringBuilder builder = new StringBuilder();
4100 if (mSettings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
4101 builder, enabledInputMethodsList, id)) {
4102 // Disabled input method is currently selected, switch to another one.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004103 final String selId = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09004104 if (id.equals(selId) && !chooseNewDefaultIMELocked()) {
4105 Slog.i(TAG, "Can't find new IME, unsetting the current input method.");
4106 resetSelectedInputMethodAndSubtypeLocked("");
satokd87c2592010-09-29 11:52:06 +09004107 }
4108 // Previous state was enabled.
4109 return true;
4110 } else {
4111 // We are disabling the input method but it is already disabled.
4112 // Nothing to do. The previous state was disabled.
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004113 return false;
4114 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004115 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004116 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08004117
satok723a27e2010-11-11 14:58:11 +09004118 private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
4119 boolean setSubtypeOnly) {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004120 mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
Tarandeep Singh89a6c482017-11-21 14:26:11 -08004121
satok723a27e2010-11-11 14:58:11 +09004122 // Set Subtype here
4123 if (imi == null || subtypeId < 0) {
4124 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
Tadashi G. Takaoka0ba75bb2010-11-09 12:19:32 -08004125 mCurrentSubtype = null;
satok723a27e2010-11-11 14:58:11 +09004126 } else {
Ken Wakasa586f0512011-01-20 22:31:01 +09004127 if (subtypeId < imi.getSubtypeCount()) {
4128 InputMethodSubtype subtype = imi.getSubtypeAt(subtypeId);
4129 mSettings.putSelectedSubtype(subtype.hashCode());
4130 mCurrentSubtype = subtype;
satok723a27e2010-11-11 14:58:11 +09004131 } else {
4132 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
satokd81e9502012-05-21 12:58:45 +09004133 // If the subtype is not specified, choose the most applicable one
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004134 mCurrentSubtype = getCurrentInputMethodSubtypeLocked();
satok723a27e2010-11-11 14:58:11 +09004135 }
satokab751aa2010-09-14 19:17:36 +09004136 }
satok723a27e2010-11-11 14:58:11 +09004137
Yohei Yukawa68645a62016-02-17 07:54:20 -08004138 if (!setSubtypeOnly) {
satok723a27e2010-11-11 14:58:11 +09004139 // Set InputMethod here
4140 mSettings.putSelectedInputMethod(imi != null ? imi.getId() : "");
4141 }
4142 }
4143
4144 private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
4145 InputMethodInfo imi = mMethodMap.get(newDefaultIme);
4146 int lastSubtypeId = NOT_A_SUBTYPE_ID;
4147 // newDefaultIme is empty when there is no candidate for the selected IME.
4148 if (imi != null && !TextUtils.isEmpty(newDefaultIme)) {
4149 String subtypeHashCode = mSettings.getLastSubtypeForInputMethodLocked(newDefaultIme);
4150 if (subtypeHashCode != null) {
4151 try {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004152 lastSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
Narayan Kamatha09b4d22016-04-15 18:32:45 +01004153 imi, Integer.parseInt(subtypeHashCode));
satok723a27e2010-11-11 14:58:11 +09004154 } catch (NumberFormatException e) {
4155 Slog.w(TAG, "HashCode for subtype looks broken: " + subtypeHashCode, e);
4156 }
4157 }
4158 }
4159 setSelectedInputMethodAndSubtypeLocked(imi, lastSubtypeId, false);
satokab751aa2010-09-14 19:17:36 +09004160 }
4161
satokab751aa2010-09-14 19:17:36 +09004162 /**
4163 * @return Return the current subtype of this input method.
4164 */
satok42c5a162011-05-26 16:46:14 +09004165 @Override
satokab751aa2010-09-14 19:17:36 +09004166 public InputMethodSubtype getCurrentInputMethodSubtype() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004167 synchronized (mMethodMap) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08004168 // TODO: Make this work even for non-current users?
Yohei Yukawa46d74762019-01-22 10:17:22 -08004169 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08004170 return null;
4171 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004172 return getCurrentInputMethodSubtypeLocked();
4173 }
4174 }
4175
4176 private InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
satokfdf419e2012-05-08 16:52:08 +09004177 if (mCurMethodId == null) {
4178 return null;
4179 }
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004180 final boolean subtypeIsSelected = mSettings.isSubtypeSelected();
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004181 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
4182 if (imi == null || imi.getSubtypeCount() == 0) {
4183 return null;
satok4e4569d2010-11-19 18:45:53 +09004184 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004185 if (!subtypeIsSelected || mCurrentSubtype == null
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004186 || !InputMethodUtils.isValidSubtypeId(imi, mCurrentSubtype.hashCode())) {
4187 int subtypeId = mSettings.getSelectedInputMethodSubtypeId(mCurMethodId);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004188 if (subtypeId == NOT_A_SUBTYPE_ID) {
4189 // If there are no selected subtypes, the framework will try to find
4190 // the most applicable subtype from explicitly or implicitly enabled
4191 // subtypes.
4192 List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004193 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004194 // If there is only one explicitly or implicitly enabled subtype,
4195 // just returns it.
4196 if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
4197 mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
4198 } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004199 mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004200 mRes, explicitlyOrImplicitlyEnabledSubtypes,
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004201 InputMethodUtils.SUBTYPE_MODE_KEYBOARD, null, true);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004202 if (mCurrentSubtype == null) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004203 mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004204 mRes, explicitlyOrImplicitlyEnabledSubtypes, null, null,
4205 true);
satok4e4569d2010-11-19 18:45:53 +09004206 }
satok3ef8b292010-11-23 06:06:29 +09004207 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004208 } else {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004209 mCurrentSubtype = InputMethodUtils.getSubtypes(imi).get(subtypeId);
satok8fbb1e82010-11-02 23:15:58 +09004210 }
4211 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004212 return mCurrentSubtype;
satokab751aa2010-09-14 19:17:36 +09004213 }
4214
Yohei Yukawaa878b952019-01-10 19:36:24 -08004215 private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
4216 synchronized (mMethodMap) {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004217 return getInputMethodListLocked(userId);
Yohei Yukawaa878b952019-01-10 19:36:24 -08004218 }
4219 }
4220
4221 private List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
4222 synchronized (mMethodMap) {
4223 return getEnabledInputMethodListLocked(userId);
4224 }
4225 }
4226
Yohei Yukawae24ed792018-08-28 19:10:32 -07004227 private static final class LocalServiceImpl extends InputMethodManagerInternal {
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004228 @NonNull
Yohei Yukawafffc0e52018-09-04 13:24:00 -07004229 private final InputMethodManagerService mService;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004230
Yohei Yukawafffc0e52018-09-04 13:24:00 -07004231 LocalServiceImpl(@NonNull InputMethodManagerService service) {
4232 mService = service;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004233 }
4234
4235 @Override
4236 public void setInteractive(boolean interactive) {
4237 // Do everything in handler so as not to block the caller.
Yohei Yukawaf16abb72018-09-05 11:28:42 -07004238 mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0)
4239 .sendToTarget();
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004240 }
Yohei Yukawaae61f712015-12-09 13:00:10 -08004241
4242 @Override
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07004243 public void hideCurrentInputMethod() {
Yohei Yukawaf16abb72018-09-05 11:28:42 -07004244 mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
4245 mService.mHandler.sendEmptyMessage(MSG_HIDE_CURRENT_INPUT_METHOD);
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07004246 }
Tarandeep Singh89a6c482017-11-21 14:26:11 -08004247
4248 @Override
Yohei Yukawaa878b952019-01-10 19:36:24 -08004249 public List<InputMethodInfo> getInputMethodListAsUser(int userId) {
4250 return mService.getInputMethodListAsUser(userId);
4251 }
4252
4253 @Override
4254 public List<InputMethodInfo> getEnabledInputMethodListAsUser(int userId) {
4255 return mService.getEnabledInputMethodListAsUser(userId);
4256 }
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004257 }
4258
Yohei Yukawac54c1172018-09-06 11:39:50 -07004259 @BinderThread
4260 private IInputContentUriToken createInputContentUriToken(@Nullable IBinder token,
Yohei Yukawa25e08132016-06-22 16:31:41 -07004261 @Nullable Uri contentUri, @Nullable String packageName) {
Yohei Yukawa25e08132016-06-22 16:31:41 -07004262 if (token == null) {
4263 throw new NullPointerException("token");
4264 }
4265 if (packageName == null) {
4266 throw new NullPointerException("packageName");
4267 }
4268 if (contentUri == null) {
4269 throw new NullPointerException("contentUri");
4270 }
4271 final String contentUriScheme = contentUri.getScheme();
4272 if (!"content".equals(contentUriScheme)) {
4273 throw new InvalidParameterException("contentUri must have content scheme");
4274 }
4275
4276 synchronized (mMethodMap) {
4277 final int uid = Binder.getCallingUid();
4278 if (mCurMethodId == null) {
4279 return null;
4280 }
4281 if (mCurToken != token) {
4282 Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + mCurToken
4283 + " token=" + token);
4284 return null;
4285 }
4286 // We cannot simply distinguish a bad IME that reports an arbitrary package name from
4287 // an unfortunate IME whose internal state is already obsolete due to the asynchronous
4288 // nature of our system. Let's compare it with our internal record.
4289 if (!TextUtils.equals(mCurAttribute.packageName, packageName)) {
4290 Slog.e(TAG, "Ignoring createInputContentUriToken mCurAttribute.packageName="
4291 + mCurAttribute.packageName + " packageName=" + packageName);
4292 return null;
4293 }
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004294 // This user ID can never bee spoofed.
Yohei Yukawa25e08132016-06-22 16:31:41 -07004295 final int imeUserId = UserHandle.getUserId(uid);
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004296 // This user ID can never bee spoofed.
Yohei Yukawa25e08132016-06-22 16:31:41 -07004297 final int appUserId = UserHandle.getUserId(mCurClient.uid);
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004298 // This user ID may be invalid if "contentUri" embedded an invalid user ID.
4299 final int contentUriOwnerUserId = ContentProvider.getUserIdFromUri(contentUri,
4300 imeUserId);
4301 final Uri contentUriWithoutUserId = ContentProvider.getUriWithoutUserId(contentUri);
4302 // Note: InputContentUriTokenHandler.take() checks whether the IME (specified by "uid")
4303 // actually has the right to grant a read permission for "contentUriWithoutUserId" that
4304 // is claimed to belong to "contentUriOwnerUserId". For example, specifying random
4305 // content URI and/or contentUriOwnerUserId just results in a SecurityException thrown
4306 // from InputContentUriTokenHandler.take() and can never be allowed beyond what is
4307 // actually allowed to "uid", which is guaranteed to be the IME's one.
4308 return new InputContentUriTokenHandler(contentUriWithoutUserId, uid,
4309 packageName, contentUriOwnerUserId, appUserId);
Yohei Yukawa25e08132016-06-22 16:31:41 -07004310 }
4311 }
4312
Yohei Yukawac54c1172018-09-06 11:39:50 -07004313 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08004314 private void reportFullscreenMode(@NonNull IBinder token, boolean fullscreen) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004315 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08004316 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004317 return;
4318 }
4319 if (mCurClient != null && mCurClient.client != null) {
4320 mInFullscreenMode = fullscreen;
4321 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
4322 MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, mCurClient));
4323 }
4324 }
4325 }
4326
4327 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004328 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06004329 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004330
4331 IInputMethod method;
4332 ClientState client;
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004333 ClientState focusedWindowClient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004335 final Printer p = new PrintWriterPrinter(pw);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004337 synchronized (mMethodMap) {
4338 p.println("Current Input Method Manager state:");
4339 int N = mMethodList.size();
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08004340 p.println(" Input Methods: mMethodMapUpdateCount=" + mMethodMapUpdateCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004341 for (int i=0; i<N; i++) {
4342 InputMethodInfo info = mMethodList.get(i);
4343 p.println(" InputMethod #" + i + ":");
4344 info.dump(p, " ");
4345 }
4346 p.println(" Clients:");
Yohei Yukawaac9311e2018-11-20 19:25:23 -08004347 final int numClients = mClients.size();
4348 for (int i = 0; i < numClients; ++i) {
4349 final ClientState ci = mClients.valueAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004350 p.println(" Client " + ci + ":");
4351 p.println(" client=" + ci.client);
4352 p.println(" inputContext=" + ci.inputContext);
4353 p.println(" sessionRequested=" + ci.sessionRequested);
4354 p.println(" curSession=" + ci.curSession);
4355 }
The Android Open Source Project10592532009-03-18 17:39:46 -07004356 p.println(" mCurMethodId=" + mCurMethodId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004357 client = mCurClient;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07004358 p.println(" mCurClient=" + client + " mCurSeq=" + mCurSeq);
Yohei Yukawa22a89232017-02-12 16:38:59 -08004359 p.println(" mCurFocusedWindow=" + mCurFocusedWindow
4360 + " softInputMode=" +
Yohei Yukawaa468d702018-10-21 11:42:34 -07004361 InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode)
Yohei Yukawa22a89232017-02-12 16:38:59 -08004362 + " client=" + mCurFocusedWindowClient);
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004363 focusedWindowClient = mCurFocusedWindowClient;
Yohei Yukawad3ef8422018-06-07 16:28:07 -07004364 p.println(" mCurId=" + mCurId + " mHaveConnection=" + mHaveConnection
4365 + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + mVisibleBound);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004366 p.println(" mCurToken=" + mCurToken);
lumark90120a82018-08-15 00:33:03 +08004367 p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004368 p.println(" mCurIntent=" + mCurIntent);
4369 method = mCurMethod;
4370 p.println(" mCurMethod=" + mCurMethod);
4371 p.println(" mEnabledSession=" + mEnabledSession);
4372 p.println(" mShowRequested=" + mShowRequested
4373 + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
4374 + " mShowForced=" + mShowForced
4375 + " mInputShown=" + mInputShown);
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004376 p.println(" mInFullscreenMode=" + mInFullscreenMode);
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004377 p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
Yohei Yukawa81482972015-06-04 00:58:59 -07004378 p.println(" mSettingsObserver=" + mSettingsObserver);
Yohei Yukawad7248862015-06-03 23:56:12 -07004379 p.println(" mSwitchingController:");
4380 mSwitchingController.dump(p);
Yohei Yukawa68645a62016-02-17 07:54:20 -08004381 p.println(" mSettings:");
4382 mSettings.dumpLocked(p, " ");
Yohei Yukawa357b2f62017-02-14 09:40:03 -08004383
4384 p.println(" mStartInputHistory:");
4385 mStartInputHistory.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004386 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004387
Jeff Brownb88102f2010-09-08 11:49:43 -07004388 p.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004389 if (client != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004390 pw.flush();
4391 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07004392 TransferPipe.dumpAsync(client.client.asBinder(), fd, args);
4393 } catch (IOException | RemoteException e) {
4394 p.println("Failed to dump input method client: " + e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004395 }
Jeff Brownb88102f2010-09-08 11:49:43 -07004396 } else {
4397 p.println("No input method client.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004398 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004399
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004400 if (focusedWindowClient != null && client != focusedWindowClient) {
4401 p.println(" ");
4402 p.println("Warning: Current input method client doesn't match the last focused. "
4403 + "window.");
4404 p.println("Dumping input method client in the last focused window just in case.");
4405 p.println(" ");
4406 pw.flush();
4407 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07004408 TransferPipe.dumpAsync(focusedWindowClient.client.asBinder(), fd, args);
4409 } catch (IOException | RemoteException e) {
4410 p.println("Failed to dump input method client in focused window: " + e);
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004411 }
4412 }
4413
Jeff Brownb88102f2010-09-08 11:49:43 -07004414 p.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004415 if (method != 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(method.asBinder(), fd, args);
4419 } catch (IOException | RemoteException e) {
4420 p.println("Failed to dump input method service: " + 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 service.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004424 }
4425 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004426
4427 @BinderThread
4428 @Override
4429 public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
4430 @Nullable FileDescriptor err,
4431 @NonNull String[] args, @Nullable ShellCallback callback,
4432 @NonNull ResultReceiver resultReceiver) throws RemoteException {
Yohei Yukawab8d240f2018-12-26 10:03:11 -08004433 final int callingUid = Binder.getCallingUid();
4434 // Reject any incoming calls from non-shell users, including ones from the system user.
4435 if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) {
4436 // Note that Binder#onTransact() will automatically close "in", "out", and "err" when
4437 // returned from this method, hence there is no need to close those FDs.
4438 // "resultReceiver" is the only thing that needs to be taken care of here.
4439 if (resultReceiver != null) {
4440 resultReceiver.send(ShellCommandResult.FAILURE, null);
4441 }
4442 final String errorMsg = "InputMethodManagerService does not support shell commands from"
4443 + " non-shell users. callingUid=" + callingUid
4444 + " args=" + Arrays.toString(args);
4445 if (Process.isCoreUid(callingUid)) {
4446 // Let's not crash the calling process if the caller is one of core components.
4447 Slog.e(TAG, errorMsg);
4448 return;
4449 }
4450 throw new SecurityException(errorMsg);
4451 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004452 new ShellCommandImpl(this).exec(
4453 this, in, out, err, args, callback, resultReceiver);
4454 }
4455
4456 private static final class ShellCommandImpl extends ShellCommand {
4457 @NonNull
4458 final InputMethodManagerService mService;
4459
4460 ShellCommandImpl(InputMethodManagerService service) {
4461 mService = service;
4462 }
4463
Yohei Yukawadb25df72018-12-27 08:40:41 -08004464 @RequiresPermission(allOf = {
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004465 Manifest.permission.DUMP,
4466 Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Yohei Yukawadb25df72018-12-27 08:40:41 -08004467 Manifest.permission.WRITE_SECURE_SETTINGS,
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004468 })
Yohei Yukawa926488d2017-12-11 17:24:55 -08004469 @BinderThread
4470 @ShellCommandResult
4471 @Override
4472 public int onCommand(@Nullable String cmd) {
Yohei Yukawadb25df72018-12-27 08:40:41 -08004473 // For shell command, require all the permissions here in favor of code simplicity.
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004474 Arrays.asList(
4475 Manifest.permission.DUMP,
4476 Manifest.permission.INTERACT_ACROSS_USERS_FULL,
4477 Manifest.permission.WRITE_SECURE_SETTINGS
4478 ).forEach(permission -> mService.mContext.enforceCallingPermission(permission, null));
Yohei Yukawadb25df72018-12-27 08:40:41 -08004479
4480 final long identity = Binder.clearCallingIdentity();
4481 try {
4482 return onCommandWithSystemIdentity(cmd);
4483 } finally {
4484 Binder.restoreCallingIdentity(identity);
4485 }
4486 }
4487
4488 @BinderThread
4489 @ShellCommandResult
4490 private int onCommandWithSystemIdentity(@Nullable String cmd) {
Yohei Yukawadfdab732018-02-21 07:16:30 +09004491 if ("refresh_debug_properties".equals(cmd)) {
4492 return refreshDebugProperties();
4493 }
4494
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08004495 if ("get-last-switch-user-id".equals(cmd)) {
4496 return mService.getLastSwitchUserId(this);
4497 }
4498
Yohei Yukawacac97722017-12-15 16:52:05 -08004499 // For existing "adb shell ime <command>".
4500 if ("ime".equals(cmd)) {
4501 final String imeCommand = getNextArg();
4502 if (imeCommand == null || "help".equals(imeCommand) || "-h".equals(imeCommand)) {
4503 onImeCommandHelp();
4504 return ShellCommandResult.SUCCESS;
4505 }
4506 switch (imeCommand) {
4507 case "list":
4508 return mService.handleShellCommandListInputMethods(this);
4509 case "enable":
4510 return mService.handleShellCommandEnableDisableInputMethod(this, true);
4511 case "disable":
4512 return mService.handleShellCommandEnableDisableInputMethod(this, false);
4513 case "set":
4514 return mService.handleShellCommandSetInputMethod(this);
4515 case "reset":
4516 return mService.handleShellCommandResetInputMethod(this);
4517 default:
4518 getOutPrintWriter().println("Unknown command: " + imeCommand);
4519 return ShellCommandResult.FAILURE;
4520 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004521 }
Yohei Yukawacac97722017-12-15 16:52:05 -08004522
4523 return handleDefaultCommands(cmd);
Yohei Yukawa926488d2017-12-11 17:24:55 -08004524 }
4525
4526 @BinderThread
Tarandeep Singh75a92392018-01-12 14:58:59 -08004527 @ShellCommandResult
4528 private int refreshDebugProperties() {
4529 DebugFlags.FLAG_OPTIMIZE_START_INPUT.refresh();
Tarandeep Singheadb1392018-11-09 18:15:57 +01004530 DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.refresh();
Tarandeep Singh75a92392018-01-12 14:58:59 -08004531 return ShellCommandResult.SUCCESS;
4532 }
4533
4534 @BinderThread
Yohei Yukawa926488d2017-12-11 17:24:55 -08004535 @Override
4536 public void onHelp() {
4537 try (PrintWriter pw = getOutPrintWriter()) {
4538 pw.println("InputMethodManagerService commands:");
4539 pw.println(" help");
4540 pw.println(" Prints this help text.");
4541 pw.println(" dump [options]");
4542 pw.println(" Synonym of dumpsys.");
Yohei Yukawacac97722017-12-15 16:52:05 -08004543 pw.println(" ime <command> [options]");
4544 pw.println(" Manipulate IMEs. Run \"ime help\" for details.");
4545 }
4546 }
4547
4548 private void onImeCommandHelp() {
4549 try (IndentingPrintWriter pw =
4550 new IndentingPrintWriter(getOutPrintWriter(), " ", 100)) {
4551 pw.println("ime <command>:");
4552 pw.increaseIndent();
4553
4554 pw.println("list [-a] [-s]");
4555 pw.increaseIndent();
4556 pw.println("prints all enabled input methods.");
4557 pw.increaseIndent();
4558 pw.println("-a: see all input methods");
4559 pw.println("-s: only a single summary line of each");
4560 pw.decreaseIndent();
4561 pw.decreaseIndent();
4562
4563 pw.println("enable <ID>");
4564 pw.increaseIndent();
4565 pw.println("allows the given input method ID to be used.");
4566 pw.decreaseIndent();
4567
4568 pw.println("disable <ID>");
4569 pw.increaseIndent();
4570 pw.println("disallows the given input method ID to be used.");
4571 pw.decreaseIndent();
4572
4573 pw.println("set <ID>");
4574 pw.increaseIndent();
4575 pw.println("switches to the given input method ID.");
4576 pw.decreaseIndent();
4577
4578 pw.println("reset");
4579 pw.increaseIndent();
4580 pw.println("reset currently selected/enabled IMEs to the default ones as if "
4581 + "the device is initially booted with the current locale.");
4582 pw.decreaseIndent();
4583
4584 pw.decreaseIndent();
Yohei Yukawa926488d2017-12-11 17:24:55 -08004585 }
4586 }
4587 }
4588
4589 // ----------------------------------------------------------------------
4590 // Shell command handlers:
4591
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08004592 @BinderThread
4593 @ShellCommandResult
4594 private int getLastSwitchUserId(@NonNull ShellCommand shellCommand) {
4595 synchronized (mMethodMap) {
4596 shellCommand.getOutPrintWriter().println(mLastSwitchUserId);
4597 return ShellCommandResult.SUCCESS;
4598 }
4599 }
4600
Yohei Yukawa926488d2017-12-11 17:24:55 -08004601 /**
4602 * Handles {@code adb shell ime list}.
4603 * @param shellCommand {@link ShellCommand} object that is handling this command.
4604 * @return Exit code of the command.
4605 */
4606 @BinderThread
4607 @ShellCommandResult
4608 private int handleShellCommandListInputMethods(@NonNull ShellCommand shellCommand) {
4609 boolean all = false;
4610 boolean brief = false;
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004611 int userIdToBeResolved = UserHandle.USER_CURRENT;
Yohei Yukawa926488d2017-12-11 17:24:55 -08004612 while (true) {
4613 final String nextOption = shellCommand.getNextOption();
4614 if (nextOption == null) {
4615 break;
4616 }
4617 switch (nextOption) {
4618 case "-a":
4619 all = true;
4620 break;
4621 case "-s":
4622 brief = true;
4623 break;
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004624 case "-u":
4625 case "--user":
4626 userIdToBeResolved = UserHandle.parseUserArg(shellCommand.getNextArgRequired());
4627 break;
Yohei Yukawa926488d2017-12-11 17:24:55 -08004628 }
4629 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004630 synchronized (mMethodMap) {
4631 final PrintWriter pr = shellCommand.getOutPrintWriter();
4632 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
4633 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
4634 for (int userId : userIds) {
4635 final List<InputMethodInfo> methods = all
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004636 ? getInputMethodListLocked(userId)
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004637 : getEnabledInputMethodListLocked(userId);
4638 if (userIds.length > 1) {
4639 pr.print("User #");
4640 pr.print(userId);
4641 pr.println(":");
4642 }
4643 for (InputMethodInfo info : methods) {
4644 if (brief) {
4645 pr.println(info.getId());
4646 } else {
4647 pr.print(info.getId());
4648 pr.println(":");
4649 info.dump(pr::println, " ");
4650 }
4651 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004652 }
4653 }
4654 return ShellCommandResult.SUCCESS;
4655 }
4656
4657 /**
4658 * Handles {@code adb shell ime enable} and {@code adb shell ime disable}.
4659 * @param shellCommand {@link ShellCommand} object that is handling this command.
4660 * @param enabled {@code true} if the command was {@code adb shell ime enable}.
4661 * @return Exit code of the command.
4662 */
4663 @BinderThread
4664 @ShellCommandResult
Yohei Yukawa926488d2017-12-11 17:24:55 -08004665 private int handleShellCommandEnableDisableInputMethod(
4666 @NonNull ShellCommand shellCommand, boolean enabled) {
Yohei Yukawa926488d2017-12-11 17:24:55 -08004667 final String id = shellCommand.getNextArgRequired();
4668
4669 final boolean previouslyEnabled;
4670 synchronized (mMethodMap) {
Yohei Yukawadb25df72018-12-27 08:40:41 -08004671 previouslyEnabled = setInputMethodEnabledLocked(id, enabled);
Yohei Yukawa926488d2017-12-11 17:24:55 -08004672 }
4673 final PrintWriter pr = shellCommand.getOutPrintWriter();
4674 pr.print("Input method ");
4675 pr.print(id);
4676 pr.print(": ");
4677 pr.print((enabled == previouslyEnabled) ? "already " : "now ");
4678 pr.println(enabled ? "enabled" : "disabled");
4679 return ShellCommandResult.SUCCESS;
4680 }
4681
4682 /**
4683 * Handles {@code adb shell ime set}.
4684 * @param shellCommand {@link ShellCommand} object that is handling this command.
4685 * @return Exit code of the command.
4686 */
4687 @BinderThread
4688 @ShellCommandResult
4689 private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) {
4690 final String id = shellCommand.getNextArgRequired();
Yohei Yukawadb25df72018-12-27 08:40:41 -08004691 synchronized (mMethodMap) {
4692 setInputMethodLocked(id, NOT_A_SUBTYPE_ID);
4693 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004694 final PrintWriter pr = shellCommand.getOutPrintWriter();
4695 pr.print("Input method ");
4696 pr.print(id);
4697 pr.println(" selected");
4698 return ShellCommandResult.SUCCESS;
4699 }
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08004700
4701 /**
4702 * Handles {@code adb shell ime reset-ime}.
4703 * @param shellCommand {@link ShellCommand} object that is handling this command.
4704 * @return Exit code of the command.
4705 */
4706 @BinderThread
4707 @ShellCommandResult
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08004708 private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08004709 synchronized (mMethodMap) {
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08004710 final String nextIme;
4711 final List<InputMethodInfo> nextEnabledImes;
Yohei Yukawadb25df72018-12-27 08:40:41 -08004712 hideCurrentInputLocked(0, null);
4713 unbindCurrentMethodLocked();
4714 // Reset the current IME
4715 resetSelectedInputMethodAndSubtypeLocked(null);
4716 // Also reset the settings of the current IME
4717 mSettings.putSelectedInputMethod(null);
4718 // Disable all enabled IMEs.
4719 mSettings.getEnabledInputMethodListLocked().forEach(
4720 imi -> setInputMethodEnabledLocked(imi.getId(), false));
4721 // Re-enable with default enabled IMEs.
4722 InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList).forEach(
4723 imi -> setInputMethodEnabledLocked(imi.getId(), true));
4724 updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
4725 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
4726 mSettings.getEnabledInputMethodListLocked(),
4727 mSettings.getCurrentUserId(),
4728 mContext.getBasePackageName());
4729 nextIme = mSettings.getSelectedInputMethod();
Yohei Yukawa9cd0c8a2019-02-04 22:25:24 -08004730 nextEnabledImes = mSettings.getEnabledInputMethodListLocked();
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08004731 final PrintWriter pr = shellCommand.getOutPrintWriter();
4732 pr.println("Reset current and enabled IMEs");
4733 pr.println("Newly selected IME:");
4734 pr.print(" "); pr.println(nextIme);
4735 pr.println("Newly enabled IMEs:");
4736 {
4737 final int N = nextEnabledImes.size();
4738 for (int i = 0; i < N; ++i) {
4739 pr.print(" ");
4740 pr.println(nextEnabledImes.get(i).getId());
4741 }
4742 }
4743 return ShellCommandResult.SUCCESS;
4744 }
4745 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07004746
4747 private static final class InputMethodPrivilegedOperationsImpl
4748 extends IInputMethodPrivilegedOperations.Stub {
4749 private final InputMethodManagerService mImms;
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08004750 @NonNull
Yohei Yukawac54c1172018-09-06 11:39:50 -07004751 private final IBinder mToken;
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08004752 InputMethodPrivilegedOperationsImpl(InputMethodManagerService imms,
4753 @NonNull IBinder token) {
Yohei Yukawac54c1172018-09-06 11:39:50 -07004754 mImms = imms;
4755 mToken = token;
4756 }
4757
4758 @BinderThread
4759 @Override
4760 public void setImeWindowStatus(int vis, int backDisposition) {
4761 mImms.setImeWindowStatus(mToken, vis, backDisposition);
4762 }
4763
4764 @BinderThread
4765 @Override
4766 public void reportStartInput(IBinder startInputToken) {
4767 mImms.reportStartInput(mToken, startInputToken);
4768 }
4769
4770 @BinderThread
4771 @Override
Yohei Yukawac54c1172018-09-06 11:39:50 -07004772 public IInputContentUriToken createInputContentUriToken(Uri contentUri,
4773 String packageName) {
4774 return mImms.createInputContentUriToken(mToken, contentUri, packageName);
4775 }
4776
4777 @BinderThread
4778 @Override
4779 public void reportFullscreenMode(boolean fullscreen) {
4780 mImms.reportFullscreenMode(mToken, fullscreen);
4781 }
Yohei Yukawac7ca3682018-09-09 20:48:38 -07004782
4783 @BinderThread
4784 @Override
4785 public void setInputMethod(String id) {
4786 mImms.setInputMethod(mToken, id);
4787 }
4788
4789 @BinderThread
4790 @Override
4791 public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
4792 mImms.setInputMethodAndSubtype(mToken, id, subtype);
4793 }
4794
4795 @BinderThread
4796 @Override
4797 public void hideMySoftInput(int flags) {
4798 mImms.hideMySoftInput(mToken, flags);
4799 }
4800
4801 @BinderThread
4802 @Override
4803 public void showMySoftInput(int flags) {
4804 mImms.showMySoftInput(mToken, flags);
4805 }
4806
4807 @BinderThread
4808 @Override
Yohei Yukawa41b094f2018-09-09 23:58:45 -07004809 public void updateStatusIcon(String packageName, @DrawableRes int iconId) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07004810 mImms.updateStatusIcon(mToken, packageName, iconId);
4811 }
4812
4813 @BinderThread
4814 @Override
4815 public boolean switchToPreviousInputMethod() {
4816 return mImms.switchToPreviousInputMethod(mToken);
4817 }
4818
4819 @BinderThread
4820 @Override
4821 public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
4822 return mImms.switchToNextInputMethod(mToken, onlyCurrentIme);
4823 }
4824
4825 @BinderThread
4826 @Override
4827 public boolean shouldOfferSwitchingToNextInputMethod() {
4828 return mImms.shouldOfferSwitchingToNextInputMethod(mToken);
4829 }
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07004830
4831 @BinderThread
4832 @Override
Yohei Yukawa9b60ba02019-01-21 00:06:27 -08004833 public void notifyUserAction() {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07004834 mImms.notifyUserAction(mToken);
4835 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08004836
4837 @BinderThread
4838 @Override
4839 public void reportPreRendered(EditorInfo info) {
4840 mImms.reportPreRendered(mToken, info);
4841 }
4842
4843 @BinderThread
4844 @Override
4845 public void applyImeVisibility(boolean setVisible) {
4846 mImms.applyImeVisibility(mToken, setVisible);
4847 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07004848 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004849}