blob: 8b6b61499e9e31bb60a8db52292d18370b7691cb [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 Yukawa0569a182018-08-28 16:09:28 -070020
Yohei Yukawafa0e47e2016-04-05 09:55:56 -070021import static java.lang.annotation.RetentionPolicy.SOURCE;
22
Yohei Yukawa926488d2017-12-11 17:24:55 -080023import android.Manifest;
Phil Weaver03a65b02018-07-19 16:07:57 -070024import android.accessibilityservice.AccessibilityService;
Tarandeep Singh75a92392018-01-12 14:58:59 -080025import android.annotation.AnyThread;
Yohei Yukawad6475a62017-04-17 10:35:27 -070026import android.annotation.BinderThread;
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +090027import android.annotation.ColorInt;
Yohei Yukawa41b094f2018-09-09 23:58:45 -070028import android.annotation.DrawableRes;
Yohei Yukawafa0e47e2016-04-05 09:55:56 -070029import android.annotation.IntDef;
Yohei Yukawa930328c2017-10-18 20:19:53 -070030import android.annotation.MainThread;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070031import android.annotation.NonNull;
Yohei Yukawae13a20fa2015-09-30 19:11:32 -070032import android.annotation.Nullable;
Yohei Yukawa926488d2017-12-11 17:24:55 -080033import android.annotation.RequiresPermission;
Yohei Yukawa7b18aec2016-03-07 13:04:32 -080034import android.annotation.UserIdInt;
Sudheer Shankadc589ac2016-11-10 15:30:17 -080035import android.app.ActivityManager;
Sudheer Shankafc46e9b2016-10-21 17:55:27 -070036import android.app.ActivityManagerInternal;
Andrew Sapperstein8a3b4cb2017-04-28 14:35:31 -070037import android.app.ActivityThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.app.AlertDialog;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070039import android.app.AppGlobals;
Yohei Yukawae63b5fa2014-09-19 13:14:55 +090040import android.app.AppOpsManager;
satokf90a33e2011-07-19 11:55:52 +090041import android.app.KeyguardManager;
satok7cfc0ed2011-06-20 21:29:36 +090042import android.app.Notification;
43import android.app.NotificationManager;
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070044import android.app.PendingIntent;
satok5b927c432012-05-01 20:09:34 +090045import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.ComponentName;
Yohei Yukawa3933a6e2016-11-10 00:47:48 -080047import android.content.ContentProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ContentResolver;
49import android.content.Context;
50import android.content.DialogInterface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.content.DialogInterface.OnCancelListener;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +090052import android.content.DialogInterface.OnClickListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.content.Intent;
satoke7c6998e2011-06-03 17:57:59 +090054import android.content.IntentFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.content.ServiceConnection;
Brandon Ballinger6da35a02009-10-21 00:38:13 -070056import android.content.pm.ApplicationInfo;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +090057import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.content.pm.PackageManager;
59import android.content.pm.ResolveInfo;
60import android.content.pm.ServiceInfo;
Amith Yamasanie861ec12010-03-24 21:39:27 -070061import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.content.res.Resources;
63import android.content.res.TypedArray;
64import android.database.ContentObserver;
Yohei Yukawab4f328a2019-05-02 08:41:27 -070065import android.graphics.Matrix;
Alan Viverette505e3ab2014-11-24 15:22:11 -080066import android.graphics.drawable.Drawable;
Yohei Yukawab4f328a2019-05-02 08:41:27 -070067import 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;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700101import android.util.SparseArray;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +0900102import android.view.ContextThemeWrapper;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700103import 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;
Adam Hebc67f2e2019-11-13 14:34:56 -0800112import android.view.autofill.AutofillId;
satokab751aa2010-09-14 19:17:36 +0900113import android.view.inputmethod.EditorInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114import android.view.inputmethod.InputBinding;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800115import android.view.inputmethod.InputConnection;
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700116import android.view.inputmethod.InputConnectionInspector;
Yohei Yukawa432cf602018-10-21 10:41:37 -0700117import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118import android.view.inputmethod.InputMethod;
119import android.view.inputmethod.InputMethodInfo;
120import android.view.inputmethod.InputMethodManager;
satokab751aa2010-09-14 19:17:36 +0900121import android.view.inputmethod.InputMethodSubtype;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900122import android.widget.ArrayAdapter;
satok01038492012-04-09 21:08:27 +0900123import android.widget.CompoundButton;
124import android.widget.CompoundButton.OnCheckedChangeListener;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900125import android.widget.RadioButton;
satok01038492012-04-09 21:08:27 +0900126import android.widget.Switch;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900127import android.widget.TextView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128
Yohei Yukawa0569a182018-08-28 16:09:28 -0700129import com.android.internal.annotations.GuardedBy;
130import com.android.internal.content.PackageMonitor;
131import com.android.internal.inputmethod.IInputContentUriToken;
Yohei Yukawac54c1172018-09-06 11:39:50 -0700132import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
Yohei Yukawaa468d702018-10-21 11:42:34 -0700133import com.android.internal.inputmethod.InputMethodDebug;
Yohei Yukawa35fa6d52018-10-31 11:33:32 -0700134import com.android.internal.inputmethod.StartInputFlags;
Yohei Yukawac6632df2018-10-21 11:47:16 -0700135import com.android.internal.inputmethod.StartInputReason;
Yohei Yukawa499e3f72018-10-21 20:15:11 -0700136import com.android.internal.inputmethod.UnbindReason;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700137import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
138import com.android.internal.notification.SystemNotificationChannels;
139import com.android.internal.os.HandlerCaller;
140import com.android.internal.os.SomeArgs;
141import com.android.internal.os.TransferPipe;
142import com.android.internal.util.DumpUtils;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700143import com.android.internal.util.IndentingPrintWriter;
Adam Hebc67f2e2019-11-13 14:34:56 -0800144import com.android.internal.view.IInlineSuggestionsRequestCallback;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700145import com.android.internal.view.IInputContext;
146import com.android.internal.view.IInputMethod;
147import com.android.internal.view.IInputMethodClient;
148import com.android.internal.view.IInputMethodManager;
149import com.android.internal.view.IInputMethodSession;
150import com.android.internal.view.IInputSessionCallback;
151import com.android.internal.view.InputBindResult;
Yohei Yukawa603f4d02018-09-11 15:04:58 -0700152import com.android.server.EventLogTags;
153import com.android.server.LocalServices;
154import com.android.server.SystemService;
Yohei Yukawae6b6e0e2018-09-12 16:42:48 -0700155import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
156import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700157import com.android.server.statusbar.StatusBarManagerService;
Adrian Roose99bc052017-11-20 17:55:31 +0100158import com.android.server.wm.WindowManagerInternal;
159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160import java.io.FileDescriptor;
161import java.io.IOException;
162import java.io.PrintWriter;
Yohei Yukawafa0e47e2016-04-05 09:55:56 -0700163import java.lang.annotation.Retention;
Yohei Yukawa25e08132016-06-22 16:31:41 -0700164import java.security.InvalidParameterException;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800165import java.text.SimpleDateFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166import java.util.ArrayList;
Yohei Yukawab8d240f2018-12-26 10:03:11 -0800167import java.util.Arrays;
satok688bd472012-02-09 20:09:17 +0900168import java.util.Collections;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800169import java.util.Date;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170import java.util.List;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800171import java.util.Locale;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800172import java.util.WeakHashMap;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800173import java.util.concurrent.atomic.AtomicInteger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174
175/**
176 * This class provides a system service that manages input methods.
177 */
178public class InputMethodManagerService extends IInputMethodManager.Stub
179 implements ServiceConnection, Handler.Callback {
180 static final boolean DEBUG = false;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700181 static final String TAG = "InputMethodManagerService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182
Yohei Yukawa926488d2017-12-11 17:24:55 -0800183 @Retention(SOURCE)
184 @IntDef({ShellCommandResult.SUCCESS, ShellCommandResult.FAILURE})
185 private @interface ShellCommandResult {
186 int SUCCESS = 0;
187 int FAILURE = -1;
188 }
189
Seigo Nonakad4474cb2015-05-04 16:53:24 -0700190 static final int MSG_SHOW_IM_SUBTYPE_PICKER = 1;
191 static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 2;
192 static final int MSG_SHOW_IM_CONFIG = 3;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 static final int MSG_UNBIND_INPUT = 1000;
195 static final int MSG_BIND_INPUT = 1010;
196 static final int MSG_SHOW_SOFT_INPUT = 1020;
197 static final int MSG_HIDE_SOFT_INPUT = 1030;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700198 static final int MSG_HIDE_CURRENT_INPUT_METHOD = 1035;
Yohei Yukawac54c1172018-09-06 11:39:50 -0700199 static final int MSG_INITIALIZE_IME = 1040;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 static final int MSG_CREATE_SESSION = 1050;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 static final int MSG_START_INPUT = 2000;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800203
Yohei Yukawa33e81792015-11-17 21:14:42 -0800204 static final int MSG_UNBIND_CLIENT = 3000;
205 static final int MSG_BIND_CLIENT = 3010;
Dianne Hackborna6e41342012-05-22 16:30:34 -0700206 static final int MSG_SET_ACTIVE = 3020;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700207 static final int MSG_SET_INTERACTIVE = 3030;
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800208 static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -0800209 static final int MSG_REPORT_PRE_RENDERED = 3060;
210 static final int MSG_APPLY_IME_VISIBILITY = 3070;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800211
satok01038492012-04-09 21:08:27 +0900212 static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
213
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -0700214 static final int MSG_SYSTEM_UNLOCK_USER = 5000;
215
Adam Hebc67f2e2019-11-13 14:34:56 -0800216 static final int MSG_INLINE_SUGGESTIONS_REQUEST = 6000;
217
Satoshi Kataokabcacc322013-10-21 17:57:27 -0700218 static final long TIME_TO_RECONNECT = 3 * 1000;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800219
satokf9f01002011-05-19 21:31:50 +0900220 static final int SECURE_SUGGESTION_SPANS_MAX_SIZE = 20;
221
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +0900222 private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
satokb6359412011-06-28 17:47:41 +0900223 private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +0900224
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700225 /**
226 * Binding flags for establishing connection to the {@link InputMethodService}.
227 */
228 private static final int IME_CONNECTION_BIND_FLAGS =
229 Context.BIND_AUTO_CREATE
230 | Context.BIND_NOT_VISIBLE
231 | Context.BIND_NOT_FOREGROUND
Yohei Yukawaad78a612017-08-04 01:57:27 -0700232 | Context.BIND_IMPORTANT_BACKGROUND;
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700233
234 /**
235 * Binding flags used only while the {@link InputMethodService} is showing window.
236 */
237 private static final int IME_VISIBLE_BIND_FLAGS =
238 Context.BIND_AUTO_CREATE
239 | Context.BIND_TREAT_LIKE_ACTIVITY
Yohei Yukawaad78a612017-08-04 01:57:27 -0700240 | Context.BIND_FOREGROUND_SERVICE
Amith Yamasanic45a9902019-04-05 16:29:30 -0700241 | Context.BIND_INCLUDE_CAPABILITIES
Yohei Yukawa59730962019-03-18 10:47:22 -0700242 | Context.BIND_SHOWING_UI
243 | Context.BIND_SCHEDULE_LIKE_TOP_APP;
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700244
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900245 /**
246 * A protected broadcast intent action for internal use for {@link PendingIntent} in
247 * the notification.
248 */
249 private static final String ACTION_SHOW_INPUT_METHOD_PICKER =
Yohei Yukawa603f4d02018-09-11 15:04:58 -0700250 "com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER";
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900251
Tarandeep Singh75a92392018-01-12 14:58:59 -0800252 /**
253 * Debug flag for overriding runtime {@link SystemProperties}.
254 */
255 @AnyThread
256 private static final class DebugFlag {
257 private static final Object LOCK = new Object();
258 private final String mKey;
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700259 private final boolean mDefaultValue;
Tarandeep Singh75a92392018-01-12 14:58:59 -0800260 @GuardedBy("LOCK")
261 private boolean mValue;
262
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700263 public DebugFlag(String key, boolean defaultValue) {
Tarandeep Singh75a92392018-01-12 14:58:59 -0800264 mKey = key;
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700265 mDefaultValue = defaultValue;
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700266 mValue = SystemProperties.getBoolean(key, defaultValue);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800267 }
268
269 void refresh() {
270 synchronized (LOCK) {
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700271 mValue = SystemProperties.getBoolean(mKey, mDefaultValue);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800272 }
273 }
274
275 boolean value() {
276 synchronized (LOCK) {
277 return mValue;
278 }
279 }
280 }
281
282 /**
283 * Debug flags that can be overridden using "adb shell setprop <key>"
284 * Note: These flags are cached. To refresh, run "adb shell ime refresh_debug_properties".
285 */
286 private static final class DebugFlags {
287 static final DebugFlag FLAG_OPTIMIZE_START_INPUT =
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700288 new DebugFlag("debug.optimize_startinput", false);
Tarandeep Singheadb1392018-11-09 18:15:57 +0100289 static final DebugFlag FLAG_PRE_RENDER_IME_VIEWS =
290 new DebugFlag("persist.pre_render_ime_views", false);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800291 }
292
Yohei Yukawaa7babbb2019-01-08 16:45:34 -0800293 @UserIdInt
294 private int mLastSwitchUserId;
Tarandeep Singh75a92392018-01-12 14:58:59 -0800295
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 final Context mContext;
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -0800297 final Resources mRes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 final Handler mHandler;
satokd87c2592010-09-29 11:52:06 +0900299 final InputMethodSettings mSettings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 final SettingsObserver mSettingsObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 final IWindowManager mIWindowManager;
Seigo Nonaka7309b122015-08-17 18:34:13 -0700302 final WindowManagerInternal mWindowManagerInternal;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700303 private final DisplayManagerInternal mDisplayManagerInternal;
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
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700436 private static final class ActivityViewInfo {
437 /**
438 * {@link ClientState} where {@link android.app.ActivityView} is running.
439 */
440 private final ClientState mParentClient;
441 /**
442 * {@link Matrix} to convert screen coordinates in the embedded virtual display to
443 * screen coordinates where {@link #mParentClient} exists.
444 */
445 private final Matrix mMatrix;
446
447 ActivityViewInfo(ClientState parentClient, Matrix matrix) {
448 mParentClient = parentClient;
449 mMatrix = matrix;
450 }
451 }
452
453 /**
454 * A mapping table from virtual display IDs created for {@link android.app.ActivityView}
455 * to its parent IME client where {@link android.app.ActivityView} is running.
456 *
457 * <p>Note: this can be used only for virtual display IDs created by
458 * {@link android.app.ActivityView}.</p>
459 */
460 private SparseArray<ActivityViewInfo> mActivityViewDisplayIdToParentMap = new SparseArray<>();
461
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 /**
Dianne Hackborna34f1ad2009-09-02 13:26:28 -0700463 * Set once the system is ready to run third party code.
464 */
465 boolean mSystemReady;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800466
Dianne Hackborna34f1ad2009-09-02 13:26:28 -0700467 /**
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700468 * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method.
469 * method. This is to be synchronized with the secure settings keyed with
470 * {@link Settings.Secure#DEFAULT_INPUT_METHOD}.
471 *
472 * <p>This can be transiently {@code null} when the system is re-initializing input method
473 * settings, e.g., the system locale is just changed.</p>
474 *
475 * <p>Note that {@link #mCurId} is used to track which IME is being connected to
476 * {@link InputMethodManagerService}.</p>
477 *
478 * @see #mCurId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 */
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700480 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481 String mCurMethodId;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800482
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 /**
484 * The current binding sequence number, incremented every time there is
485 * a new bind performed.
486 */
487 int mCurSeq;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 /**
490 * The client that is currently bound to an input method.
491 */
492 ClientState mCurClient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 /**
Yohei Yukawae39d4ed2015-11-19 03:38:49 -0800495 * The last window token that we confirmed to be focused. This is always updated upon reports
496 * from the input method client. If the window state is already changed before the report is
497 * handled, this field just keeps the last value.
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700498 */
499 IBinder mCurFocusedWindow;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800500
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700501 /**
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -0700502 * The last window token that we confirmed that IME started talking to. This is always updated
503 * upon reports from the input method. If the window state is already changed before the report
504 * is handled, this field just keeps the last value.
505 */
506 IBinder mLastImeTargetWindow;
507
508 /**
Yohei Yukawa6e875592019-01-28 00:49:30 -0800509 * {@link LayoutParams#softInputMode} of {@link #mCurFocusedWindow}.
Yohei Yukawa22a89232017-02-12 16:38:59 -0800510 *
511 * @see #mCurFocusedWindow
512 */
Yohei Yukawab0c26452018-10-21 10:42:52 -0700513 @SoftInputModeFlags
Yohei Yukawa22a89232017-02-12 16:38:59 -0800514 int mCurFocusedWindowSoftInputMode;
515
516 /**
Tarandeep Singheb570612018-01-29 16:20:32 -0800517 * The client by which {@link #mCurFocusedWindow} was reported.
Yohei Yukawae39d4ed2015-11-19 03:38:49 -0800518 */
519 ClientState mCurFocusedWindowClient;
520
521 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 * The input context last provided by the current client.
523 */
524 IInputContext mCurInputContext;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800525
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 /**
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700527 * The missing method flags for the input context last provided by the current client.
528 *
529 * @see android.view.inputmethod.InputConnectionInspector.MissingMethodFlags
530 */
Yohei Yukawa432cf602018-10-21 10:41:37 -0700531 @MissingMethodFlags
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700532 int mCurInputContextMissingMethods;
533
534 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 * The attributes last provided by the current client.
536 */
537 EditorInfo mCurAttribute;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800538
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 /**
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700540 * A special {@link Matrix} to convert virtual screen coordinates to the IME target display
541 * coordinates.
542 *
543 * <p>Used only while the IME client is running in a virtual display inside
544 * {@link android.app.ActivityView}. {@code null} otherwise.</p>
545 */
546 @Nullable
547 private Matrix mCurActivityViewToScreenMatrix = null;
548
549 /**
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700550 * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 * connected to or in the process of connecting to.
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700552 *
553 * <p>This can be {@code null} when no input method is connected.</p>
554 *
555 * @see #mCurMethodId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 */
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700557 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 String mCurId;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 /**
satokab751aa2010-09-14 19:17:36 +0900561 * The current subtype of the current input method.
562 */
563 private InputMethodSubtype mCurrentSubtype;
564
John Spurlocke0980502013-10-25 11:59:29 -0400565 // Was the keyguard locked when this client became current?
566 private boolean mCurClientInKeyguard;
567
satokab751aa2010-09-14 19:17:36 +0900568 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 * Set to true if our ServiceConnection is currently actively bound to
570 * a service (whether or not we have gotten its IBinder back yet).
571 */
572 boolean mHaveConnection;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 /**
575 * Set if the client has asked for the input method to be shown.
576 */
577 boolean mShowRequested;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800578
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 /**
580 * Set if we were explicitly told to show the input method.
581 */
582 boolean mShowExplicitlyRequested;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 /**
585 * Set if we were forced to be shown.
586 */
587 boolean mShowForced;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 /**
590 * Set if we last told the input method to show itself.
591 */
592 boolean mInputShown;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 /**
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800595 * {@code true} if the current input method is in fullscreen mode.
596 */
597 boolean mInFullscreenMode;
598
599 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 * The Intent used to connect to the current input method.
601 */
602 Intent mCurIntent;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 /**
605 * The token we have made for the currently active input method, to
606 * identify it in the future.
607 */
608 IBinder mCurToken;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 /**
lumark90120a82018-08-15 00:33:03 +0800611 * The displayId of current active input method.
612 */
613 int mCurTokenDisplayId = INVALID_DISPLAY;
614
lumark7570cac2019-03-07 22:14:38 +0800615 /**
616 * The display ID of the input method indicates the fallback display which returned by
617 * {@link #computeImeDisplayIdForTarget}.
618 */
619 private static final int FALLBACK_DISPLAY_ID = DEFAULT_DISPLAY;
620
lumarkef1965b2018-09-12 17:42:53 +0800621 final ImeDisplayValidator mImeDisplayValidator;
622
lumark90120a82018-08-15 00:33:03 +0800623 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 * If non-null, this is the input method service we are currently connected
625 * to.
626 */
627 IInputMethod mCurMethod;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 /**
630 * Time that we last initiated a bind to the input method, to determine
631 * if we should try to disconnect and reconnect to it.
632 */
633 long mLastBindTime;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 /**
636 * Have we called mCurMethod.bindInput()?
637 */
638 boolean mBoundToMethod;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800639
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 /**
641 * Currently enabled session. Only touched by service thread, not
642 * protected by a lock.
643 */
644 SessionState mEnabledSession;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 /**
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700647 * True if the device is currently interactive with user. The value is true initially.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 */
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700649 boolean mIsInteractive = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800650
Joe Onorato857fd9b2011-01-27 15:08:35 -0800651 int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900652
653 /**
654 * A set of status bits regarding the active IME.
655 *
656 * <p>This value is a combination of following two bits:</p>
657 * <dl>
658 * <dt>{@link InputMethodService#IME_ACTIVE}</dt>
659 * <dd>
660 * If this bit is ON, connected IME is ready to accept touch/key events.
661 * </dd>
662 * <dt>{@link InputMethodService#IME_VISIBLE}</dt>
663 * <dd>
664 * If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
665 * </dd>
Tarandeep Singheadb1392018-11-09 18:15:57 +0100666 * dt>{@link InputMethodService#IME_INVISIBLE}</dt>
667 * <dd> If this bit is ON, IME is ready with views from last EditorInfo but is
668 * currently invisible.
669 * </dd>
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900670 * </dl>
lumark7570cac2019-03-07 22:14:38 +0800671 * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
672 * {@link #unbindCurrentMethodLocked()}.</em>
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900673 */
Joe Onorato857fd9b2011-01-27 15:08:35 -0800674 int mImeWindowVis;
675
Ken Wakasa05dbb652011-08-22 15:22:43 +0900676 private AlertDialog.Builder mDialogBuilder;
677 private AlertDialog mSwitchingDialog;
Wale Ogunwale3a931692016-11-02 16:49:48 -0700678 private IBinder mSwitchingDialogToken = new Binder();
satok01038492012-04-09 21:08:27 +0900679 private View mSwitchingDialogTitleView;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900680 private InputMethodInfo[] mIms;
681 private int[] mSubtypeIds;
Yohei Yukawae985c242016-02-24 18:27:04 -0800682 private LocaleList mLastSystemLocales;
Michael Wright7b5a96b2014-08-09 19:28:42 -0700683 private boolean mShowImeWithHardKeyboard;
Anna Galusza9b278112016-01-04 11:37:37 -0800684 private boolean mAccessibilityRequestingNoSoftKeyboard;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +0900685 private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
686 private final IPackageManager mIPackageManager;
Jason Monk3e189872016-01-12 09:10:34 -0500687 private final String mSlotIme;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800688
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800689 /**
690 * Internal state snapshot when {@link #MSG_START_INPUT} message is about to be posted to the
691 * internal message queue. Any subsequent state change inside {@link InputMethodManagerService}
692 * will not affect those tasks that are already posted.
693 *
694 * <p>Posting {@link #MSG_START_INPUT} message basically means that
695 * {@link InputMethodService#doStartInput(InputConnection, EditorInfo, boolean)} will be called
696 * back in the current IME process shortly, which will also affect what the current IME starts
697 * receiving from {@link InputMethodService#getCurrentInputConnection()}. In other words, this
698 * snapshot will be taken every time when {@link InputMethodManagerService} is initiating a new
699 * logical input session between the client application and the current IME.</p>
700 *
701 * <p>Be careful to not keep strong references to this object forever, which can prevent
702 * {@link StartInputInfo#mImeToken} and {@link StartInputInfo#mTargetWindow} from being GC-ed.
703 * </p>
704 */
705 private static class StartInputInfo {
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800706 private static final AtomicInteger sSequenceNumber = new AtomicInteger(0);
707
708 final int mSequenceNumber;
709 final long mTimestamp;
710 final long mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800711 @UserIdInt
712 final int mImeUserId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800713 @NonNull
714 final IBinder mImeToken;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800715 final int mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800716 @NonNull
717 final String mImeId;
Yohei Yukawadc66e522018-10-21 10:43:14 -0700718 @StartInputReason
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800719 final int mStartInputReason;
720 final boolean mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800721 @UserIdInt
722 final int mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800723 final int mTargetDisplayId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800724 @Nullable
725 final IBinder mTargetWindow;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800726 @NonNull
727 final EditorInfo mEditorInfo;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700728 @SoftInputModeFlags
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800729 final int mTargetWindowSoftInputMode;
730 final int mClientBindSequenceNumber;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800731
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800732 StartInputInfo(@UserIdInt int imeUserId, @NonNull IBinder imeToken, int imeDisplayId,
733 @NonNull String imeId, @StartInputReason int startInputReason, boolean restarting,
734 @UserIdInt int targetUserId, int targetDisplayId, @Nullable IBinder targetWindow,
735 @NonNull EditorInfo editorInfo, @SoftInputModeFlags int targetWindowSoftInputMode,
736 int clientBindSequenceNumber) {
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800737 mSequenceNumber = sSequenceNumber.getAndIncrement();
738 mTimestamp = SystemClock.uptimeMillis();
739 mWallTime = System.currentTimeMillis();
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800740 mImeUserId = imeUserId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800741 mImeToken = imeToken;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800742 mImeDisplayId = imeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800743 mImeId = imeId;
744 mStartInputReason = startInputReason;
745 mRestarting = restarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800746 mTargetUserId = targetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800747 mTargetDisplayId = targetDisplayId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800748 mTargetWindow = targetWindow;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800749 mEditorInfo = editorInfo;
750 mTargetWindowSoftInputMode = targetWindowSoftInputMode;
751 mClientBindSequenceNumber = clientBindSequenceNumber;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800752 }
753 }
754
Yohei Yukawab37d8bd2017-02-13 18:29:05 -0800755 @GuardedBy("mMethodMap")
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -0700756 private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800757
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800758 /**
759 * A ring buffer to store the history of {@link StartInputInfo}.
760 */
761 private static final class StartInputHistory {
762 /**
763 * Entry size for non low-RAM devices.
764 *
765 * <p>TODO: Consider to follow what other system services have been doing to manage
766 * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
767 */
768 private final static int ENTRY_SIZE_FOR_HIGH_RAM_DEVICE = 16;
769
770 /**
771 * Entry size for non low-RAM devices.
772 *
773 * <p>TODO: Consider to follow what other system services have been doing to manage
774 * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
775 */
776 private final static int ENTRY_SIZE_FOR_LOW_RAM_DEVICE = 5;
777
778 private static int getEntrySize() {
779 if (ActivityManager.isLowRamDeviceStatic()) {
780 return ENTRY_SIZE_FOR_LOW_RAM_DEVICE;
781 } else {
782 return ENTRY_SIZE_FOR_HIGH_RAM_DEVICE;
783 }
784 }
785
786 /**
787 * Backing store for the ring bugger.
788 */
789 private final Entry[] mEntries = new Entry[getEntrySize()];
790
791 /**
792 * An index of {@link #mEntries}, to which next {@link #addEntry(StartInputInfo)} should
793 * write.
794 */
795 private int mNextIndex = 0;
796
797 /**
798 * Recyclable entry to store the information in {@link StartInputInfo}.
799 */
800 private static final class Entry {
801 int mSequenceNumber;
802 long mTimestamp;
803 long mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800804 @UserIdInt
805 int mImeUserId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800806 @NonNull
807 String mImeTokenString;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800808 int mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800809 @NonNull
810 String mImeId;
Yohei Yukawadc66e522018-10-21 10:43:14 -0700811 @StartInputReason
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800812 int mStartInputReason;
813 boolean mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800814 @UserIdInt
815 int mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800816 int mTargetDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800817 @NonNull
818 String mTargetWindowString;
819 @NonNull
820 EditorInfo mEditorInfo;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700821 @SoftInputModeFlags
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800822 int mTargetWindowSoftInputMode;
823 int mClientBindSequenceNumber;
824
825 Entry(@NonNull StartInputInfo original) {
826 set(original);
827 }
828
829 void set(@NonNull StartInputInfo original) {
830 mSequenceNumber = original.mSequenceNumber;
831 mTimestamp = original.mTimestamp;
832 mWallTime = original.mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800833 mImeUserId = original.mImeUserId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800834 // Intentionally convert to String so as not to keep a strong reference to a Binder
835 // object.
836 mImeTokenString = String.valueOf(original.mImeToken);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800837 mImeDisplayId = original.mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800838 mImeId = original.mImeId;
839 mStartInputReason = original.mStartInputReason;
840 mRestarting = original.mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800841 mTargetUserId = original.mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800842 mTargetDisplayId = original.mTargetDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800843 // Intentionally convert to String so as not to keep a strong reference to a Binder
844 // object.
845 mTargetWindowString = String.valueOf(original.mTargetWindow);
846 mEditorInfo = original.mEditorInfo;
847 mTargetWindowSoftInputMode = original.mTargetWindowSoftInputMode;
848 mClientBindSequenceNumber = original.mClientBindSequenceNumber;
849 }
850 }
851
852 /**
853 * Add a new entry and discard the oldest entry as needed.
854 * @param info {@lin StartInputInfo} to be added.
855 */
856 void addEntry(@NonNull StartInputInfo info) {
857 final int index = mNextIndex;
858 if (mEntries[index] == null) {
859 mEntries[index] = new Entry(info);
860 } else {
861 mEntries[index].set(info);
862 }
863 mNextIndex = (mNextIndex + 1) % mEntries.length;
864 }
865
866 void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
867 final SimpleDateFormat dataFormat =
868 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
869
870 for (int i = 0; i < mEntries.length; ++i) {
871 final Entry entry = mEntries[(i + mNextIndex) % mEntries.length];
872 if (entry == null) {
873 continue;
874 }
875 pw.print(prefix);
876 pw.println("StartInput #" + entry.mSequenceNumber + ":");
877
878 pw.print(prefix);
879 pw.println(" time=" + dataFormat.format(new Date(entry.mWallTime))
880 + " (timestamp=" + entry.mTimestamp + ")"
881 + " reason="
Yohei Yukawaa468d702018-10-21 11:42:34 -0700882 + InputMethodDebug.startInputReasonToString(entry.mStartInputReason)
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800883 + " restarting=" + entry.mRestarting);
884
885 pw.print(prefix);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800886 pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]");
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800887 pw.print(" imeUserId=" + entry.mImeUserId);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800888 pw.println(" imeDisplayId=" + entry.mImeDisplayId);
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800889
890 pw.print(prefix);
891 pw.println(" targetWin=" + entry.mTargetWindowString
892 + " [" + entry.mEditorInfo.packageName + "]"
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800893 + " targetUserId=" + entry.mTargetUserId
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800894 + " targetDisplayId=" + entry.mTargetDisplayId
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800895 + " clientBindSeq=" + entry.mClientBindSequenceNumber);
896
897 pw.print(prefix);
Yohei Yukawaa468d702018-10-21 11:42:34 -0700898 pw.println(" softInputMode=" + InputMethodDebug.softInputModeToString(
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800899 entry.mTargetWindowSoftInputMode));
900
901 pw.print(prefix);
902 pw.println(" inputType=0x" + Integer.toHexString(entry.mEditorInfo.inputType)
903 + " imeOptions=0x" + Integer.toHexString(entry.mEditorInfo.imeOptions)
904 + " fieldId=0x" + Integer.toHexString(entry.mEditorInfo.fieldId)
905 + " fieldName=" + entry.mEditorInfo.fieldName
906 + " actionId=" + entry.mEditorInfo.actionId
907 + " actionLabel=" + entry.mEditorInfo.actionLabel);
908 }
909 }
910 }
911
912 @GuardedBy("mMethodMap")
913 @NonNull
914 private final StartInputHistory mStartInputHistory = new StartInputHistory();
915
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 class SettingsObserver extends ContentObserver {
Yohei Yukawa81482972015-06-04 00:58:59 -0700917 int mUserId;
918 boolean mRegistered = false;
Yohei Yukawa7b574cb2016-03-16 17:22:22 -0700919 @NonNull
Dianne Hackbornfd7aded2013-01-22 17:10:23 -0800920 String mLastEnabled = "";
921
Yohei Yukawa81482972015-06-04 00:58:59 -0700922 /**
923 * <em>This constructor must be called within the lock.</em>
924 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925 SettingsObserver(Handler handler) {
926 super(handler);
Yohei Yukawa81482972015-06-04 00:58:59 -0700927 }
928
Yohei Yukawa7b18aec2016-03-07 13:04:32 -0800929 public void registerContentObserverLocked(@UserIdInt int userId) {
Yohei Yukawa81482972015-06-04 00:58:59 -0700930 if (mRegistered && mUserId == userId) {
931 return;
932 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 ContentResolver resolver = mContext.getContentResolver();
Yohei Yukawa81482972015-06-04 00:58:59 -0700934 if (mRegistered) {
935 mContext.getContentResolver().unregisterContentObserver(this);
936 mRegistered = false;
937 }
938 if (mUserId != userId) {
939 mLastEnabled = "";
940 mUserId = userId;
941 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700943 Settings.Secure.DEFAULT_INPUT_METHOD), false, this, userId);
satokab751aa2010-09-14 19:17:36 +0900944 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700945 Settings.Secure.ENABLED_INPUT_METHODS), false, this, userId);
satokb6109bb2011-02-03 22:24:54 +0900946 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700947 Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, userId);
Michael Wright7b5a96b2014-08-09 19:28:42 -0700948 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700949 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
Anna Galusza9b278112016-01-04 11:37:37 -0800950 resolver.registerContentObserver(Settings.Secure.getUriFor(
951 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, userId);
Yohei Yukawa81482972015-06-04 00:58:59 -0700952 mRegistered = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800954
Michael Wright7b5a96b2014-08-09 19:28:42 -0700955 @Override public void onChange(boolean selfChange, Uri uri) {
Anna Galusza9b278112016-01-04 11:37:37 -0800956 final Uri showImeUri = Settings.Secure.getUriFor(
957 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
958 final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
959 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 synchronized (mMethodMap) {
Michael Wright7b5a96b2014-08-09 19:28:42 -0700961 if (showImeUri.equals(uri)) {
962 updateKeyboardFromSettingsLocked();
Anna Galusza9b278112016-01-04 11:37:37 -0800963 } else if (accessibilityRequestingNoImeUri.equals(uri)) {
Phil Weaver03a65b02018-07-19 16:07:57 -0700964 final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
Anna Galusza9b278112016-01-04 11:37:37 -0800965 mContext.getContentResolver(),
Phil Weaver03a65b02018-07-19 16:07:57 -0700966 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, mUserId);
967 mAccessibilityRequestingNoSoftKeyboard =
968 (accessibilitySoftKeyboardSetting & AccessibilityService.SHOW_MODE_MASK)
969 == AccessibilityService.SHOW_MODE_HIDDEN;
Anna Galusza9b278112016-01-04 11:37:37 -0800970 if (mAccessibilityRequestingNoSoftKeyboard) {
971 final boolean showRequested = mShowRequested;
972 hideCurrentInputLocked(0, null);
973 mShowRequested = showRequested;
974 } else if (mShowRequested) {
975 showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
976 }
Michael Wright7b5a96b2014-08-09 19:28:42 -0700977 } else {
978 boolean enabledChanged = false;
979 String newEnabled = mSettings.getEnabledInputMethodsStr();
980 if (!mLastEnabled.equals(newEnabled)) {
981 mLastEnabled = newEnabled;
982 enabledChanged = true;
983 }
984 updateInputMethodsFromSettingsLocked(enabledChanged);
Dianne Hackbornfd7aded2013-01-22 17:10:23 -0800985 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 }
987 }
Yohei Yukawa81482972015-06-04 00:58:59 -0700988
989 @Override
990 public String toString() {
991 return "SettingsObserver{mUserId=" + mUserId + " mRegistered=" + mRegistered
992 + " mLastEnabled=" + mLastEnabled + "}";
993 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800995
Yohei Yukawa0ec08002019-03-08 10:48:26 -0800996 /**
997 * {@link BroadcastReceiver} that is intended to listen to broadcasts sent to the system user
998 * only.
999 */
1000 private final class ImmsBroadcastReceiverForSystemUser extends BroadcastReceiver {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001001 @Override
1002 public void onReceive(Context context, Intent intent) {
1003 final String action = intent.getAction();
Yohei Yukawa4225c7d2019-03-08 00:06:11 -08001004 if (Intent.ACTION_USER_ADDED.equals(action)
Amith Yamasani734983f2014-03-04 16:48:05 -08001005 || Intent.ACTION_USER_REMOVED.equals(action)) {
Kenny Guy2a764942014-04-02 13:29:20 +01001006 updateCurrentProfileIds();
Amith Yamasani734983f2014-03-04 16:48:05 -08001007 return;
Yohei Yukawa79247822017-01-23 15:26:15 -08001008 } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001009 onActionLocaleChanged();
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001010 } else if (ACTION_SHOW_INPUT_METHOD_PICKER.equals(action)) {
1011 // ACTION_SHOW_INPUT_METHOD_PICKER action is a protected-broadcast and it is
1012 // guaranteed to be send only from the system, so that there is no need for extra
1013 // security check such as
1014 // {@link #canShowInputMethodPickerLocked(IInputMethodClient)}.
1015 mHandler.obtainMessage(
1016 MSG_SHOW_IM_SUBTYPE_PICKER,
lumark0b05f9e2018-11-26 15:09:06 +08001017 // TODO(b/120076400): Design and implement IME switcher for heterogeneous
1018 // navbar configuration.
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001019 InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES,
lumark0b05f9e2018-11-26 15:09:06 +08001020 DEFAULT_DISPLAY).sendToTarget();
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001021 } else {
1022 Slog.w(TAG, "Unexpected intent " + intent);
1023 }
1024 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001026
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001027 /**
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001028 * {@link BroadcastReceiver} that is intended to listen to broadcasts sent to all the users.
1029 */
1030 private final class ImmsBroadcastReceiverForAllUsers extends BroadcastReceiver {
1031 @Override
1032 public void onReceive(Context context, Intent intent) {
1033 final String action = intent.getAction();
1034 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
1035 final PendingResult pendingResult = getPendingResult();
1036 if (pendingResult == null) {
1037 return;
1038 }
1039 // sender userId can be a real user ID or USER_ALL.
1040 final int senderUserId = pendingResult.getSendingUserId();
1041 if (senderUserId != UserHandle.USER_ALL) {
Tarandeep Singhcf5ff822019-07-08 14:06:27 -07001042 if (senderUserId != mSettings.getCurrentUserId()) {
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001043 // A background user is trying to hide the dialog. Ignore.
1044 return;
1045 }
1046 }
1047 hideInputMethodMenu();
1048 } else {
1049 Slog.w(TAG, "Unexpected intent " + intent);
1050 }
1051 }
1052 }
1053
1054 /**
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001055 * Handles {@link Intent#ACTION_LOCALE_CHANGED}.
1056 *
1057 * <p>Note: For historical reasons, {@link Intent#ACTION_LOCALE_CHANGED} has been sent to all
1058 * the users. We should ignore this event if this is about any background user's locale.</p>
1059 *
1060 * <p>Caution: This method must not be called when system is not ready.</p>
1061 */
1062 void onActionLocaleChanged() {
1063 synchronized (mMethodMap) {
1064 final LocaleList possibleNewLocale = mRes.getConfiguration().getLocales();
1065 if (possibleNewLocale != null && possibleNewLocale.equals(mLastSystemLocales)) {
1066 return;
1067 }
1068 buildInputMethodListLocked(true);
1069 // If the locale is changed, needs to reset the default ime
1070 resetDefaultImeLocked(mContext);
1071 updateFromSettingsLocked(true);
1072 mLastSystemLocales = possibleNewLocale;
1073 }
1074 }
1075
Yohei Yukawac4e44912017-02-09 19:30:22 -08001076 final class MyPackageMonitor extends PackageMonitor {
1077 /**
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001078 * Package names that are known to contain {@link InputMethodService}.
Yohei Yukawac4e44912017-02-09 19:30:22 -08001079 *
1080 * <p>No need to include packages because of direct-boot unaware IMEs since we always rescan
1081 * all the packages when the user is unlocked, and direct-boot awareness will not be changed
1082 * dynamically unless the entire package is updated, which also always triggers package
1083 * rescanning.</p>
1084 */
1085 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001086 final private ArraySet<String> mKnownImePackageNames = new ArraySet<>();
1087
1088 /**
1089 * Packages that are appeared, disappeared, or modified for whatever reason.
1090 *
1091 * <p>Note: For now we intentionally use {@link ArrayList} instead of {@link ArraySet}
1092 * because 1) the number of elements is almost always 1 or so, and 2) we do not care
1093 * duplicate elements for our use case.</p>
1094 *
1095 * <p>This object must be accessed only from callback methods in {@link PackageMonitor},
1096 * which should be bound to {@link #getRegisteredHandler()}.</p>
1097 */
1098 private final ArrayList<String> mChangedPackages = new ArrayList<>();
1099
1100 /**
1101 * {@code true} if one or more packages that contain {@link InputMethodService} appeared.
1102 *
1103 * <p>This field must be accessed only from callback methods in {@link PackageMonitor},
1104 * which should be bound to {@link #getRegisteredHandler()}.</p>
1105 */
1106 private boolean mImePackageAppeared = false;
Yohei Yukawac4e44912017-02-09 19:30:22 -08001107
1108 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001109 void clearKnownImePackageNamesLocked() {
1110 mKnownImePackageNames.clear();
Yohei Yukawac4e44912017-02-09 19:30:22 -08001111 }
1112
1113 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001114 final void addKnownImePackageNameLocked(@NonNull String packageName) {
1115 mKnownImePackageNames.add(packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08001116 }
1117
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001118 @GuardedBy("mMethodMap")
1119 private boolean isChangingPackagesOfCurrentUserLocked() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001120 final int userId = getChangingUserId();
1121 final boolean retval = userId == mSettings.getCurrentUserId();
1122 if (DEBUG) {
satok81f8b7c2012-12-04 20:42:56 +09001123 if (!retval) {
1124 Slog.d(TAG, "--- ignore this call back from a background user: " + userId);
1125 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001126 }
1127 return retval;
1128 }
1129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001131 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 synchronized (mMethodMap) {
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001133 if (!isChangingPackagesOfCurrentUserLocked()) {
1134 return false;
1135 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001136 String curInputMethodId = mSettings.getSelectedInputMethod();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 final int N = mMethodList.size();
1138 if (curInputMethodId != null) {
1139 for (int i=0; i<N; i++) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001140 InputMethodInfo imi = mMethodList.get(i);
1141 if (imi.getId().equals(curInputMethodId)) {
1142 for (String pkg : packages) {
1143 if (imi.getPackageName().equals(pkg)) {
1144 if (!doit) {
1145 return true;
1146 }
satok723a27e2010-11-11 14:58:11 +09001147 resetSelectedInputMethodAndSubtypeLocked("");
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001148 chooseNewDefaultIMELocked();
1149 return true;
1150 }
1151 }
1152 }
1153 }
1154 }
1155 }
1156 return false;
1157 }
1158
1159 @Override
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001160 public void onBeginPackageChanges() {
1161 clearPackageChangeState();
1162 }
1163
1164 @Override
1165 public void onPackageAppeared(String packageName, int reason) {
1166 if (!mImePackageAppeared) {
1167 final PackageManager pm = mContext.getPackageManager();
1168 final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
1169 new Intent(InputMethod.SERVICE_INTERFACE).setPackage(packageName),
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08001170 PackageManager.MATCH_DISABLED_COMPONENTS, getChangingUserId());
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001171 // No need to lock this because we access it only on getRegisteredHandler().
1172 if (!services.isEmpty()) {
1173 mImePackageAppeared = true;
1174 }
1175 }
1176 // No need to lock this because we access it only on getRegisteredHandler().
1177 mChangedPackages.add(packageName);
1178 }
1179
1180 @Override
1181 public void onPackageDisappeared(String packageName, int reason) {
1182 // No need to lock this because we access it only on getRegisteredHandler().
1183 mChangedPackages.add(packageName);
1184 }
1185
1186 @Override
1187 public void onPackageModified(String packageName) {
1188 // No need to lock this because we access it only on getRegisteredHandler().
1189 mChangedPackages.add(packageName);
1190 }
1191
1192 @Override
1193 public void onPackagesSuspended(String[] packages) {
1194 // No need to lock this because we access it only on getRegisteredHandler().
1195 for (String packageName : packages) {
1196 mChangedPackages.add(packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08001197 }
1198 }
1199
1200 @Override
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001201 public void onPackagesUnsuspended(String[] packages) {
1202 // No need to lock this because we access it only on getRegisteredHandler().
1203 for (String packageName : packages) {
1204 mChangedPackages.add(packageName);
1205 }
1206 }
1207
1208 @Override
1209 public void onFinishPackageChanges() {
1210 onFinishPackageChangesInternal();
1211 clearPackageChangeState();
1212 }
1213
1214 private void clearPackageChangeState() {
1215 // No need to lock them because we access these fields only on getRegisteredHandler().
1216 mChangedPackages.clear();
1217 mImePackageAppeared = false;
1218 }
1219
Andreas Gampea36dc622018-02-05 17:19:22 -08001220 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001221 private boolean shouldRebuildInputMethodListLocked() {
1222 // This method is guaranteed to be called only by getRegisteredHandler().
1223
1224 // If there is any new package that contains at least one IME, then rebuilt the list
1225 // of IMEs.
1226 if (mImePackageAppeared) {
1227 return true;
1228 }
1229
1230 // Otherwise, check if mKnownImePackageNames and mChangedPackages have any intersection.
1231 // TODO: Consider to create a utility method to do the following test. List.retainAll()
1232 // is an option, but it may still do some extra operations that we do not need here.
1233 final int N = mChangedPackages.size();
1234 for (int i = 0; i < N; ++i) {
1235 final String packageName = mChangedPackages.get(i);
1236 if (mKnownImePackageNames.contains(packageName)) {
1237 return true;
1238 }
1239 }
1240 return false;
1241 }
1242
1243 private void onFinishPackageChangesInternal() {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001244 synchronized (mMethodMap) {
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001245 if (!isChangingPackagesOfCurrentUserLocked()) {
1246 return;
1247 }
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001248 if (!shouldRebuildInputMethodListLocked()) {
1249 return;
1250 }
1251
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001252 InputMethodInfo curIm = null;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001253 String curInputMethodId = mSettings.getSelectedInputMethod();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001254 final int N = mMethodList.size();
1255 if (curInputMethodId != null) {
1256 for (int i=0; i<N; i++) {
1257 InputMethodInfo imi = mMethodList.get(i);
satoke7c6998e2011-06-03 17:57:59 +09001258 final String imiId = imi.getId();
1259 if (imiId.equals(curInputMethodId)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001260 curIm = imi;
1261 }
satoke7c6998e2011-06-03 17:57:59 +09001262
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001263 int change = isPackageDisappearing(imi.getPackageName());
satoke7c6998e2011-06-03 17:57:59 +09001264 if (isPackageModified(imi.getPackageName())) {
Yohei Yukawab557d572018-12-29 21:26:26 -08001265 mAdditionalSubtypeMap.remove(imi.getId());
1266 AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
1267 mSettings.getCurrentUserId());
satoke7c6998e2011-06-03 17:57:59 +09001268 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001269 if (change == PACKAGE_TEMPORARY_CHANGE
1270 || change == PACKAGE_PERMANENT_CHANGE) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001271 Slog.i(TAG, "Input method uninstalled, disabling: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001272 + imi.getComponent());
1273 setInputMethodEnabledLocked(imi.getId(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 }
1275 }
1276 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001277
Yohei Yukawa94e33302016-02-12 19:37:03 -08001278 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 boolean changed = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001281
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001282 if (curIm != null) {
Anna Galusza9b278112016-01-04 11:37:37 -08001283 int change = isPackageDisappearing(curIm.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001284 if (change == PACKAGE_TEMPORARY_CHANGE
1285 || change == PACKAGE_PERMANENT_CHANGE) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001286 ServiceInfo si = null;
1287 try {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001288 si = mIPackageManager.getServiceInfo(
1289 curIm.getComponent(), 0, mSettings.getCurrentUserId());
1290 } catch (RemoteException ex) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001291 }
1292 if (si == null) {
1293 // Uh oh, current input method is no longer around!
1294 // Pick another one...
Joe Onorato8a9b2202010-02-26 18:56:32 -08001295 Slog.i(TAG, "Current input method removed: " + curInputMethodId);
Yohei Yukawa849443c2019-01-21 09:02:25 -08001296 updateSystemUiLocked(0 /* vis */, mBackDisposition);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001297 if (!chooseNewDefaultIMELocked()) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001298 changed = true;
1299 curIm = null;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001300 Slog.i(TAG, "Unsetting current input method");
satok723a27e2010-11-11 14:58:11 +09001301 resetSelectedInputMethodAndSubtypeLocked("");
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001302 }
1303 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001304 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001305 }
satokab751aa2010-09-14 19:17:36 +09001306
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001307 if (curIm == null) {
1308 // We currently don't have a default input method... is
1309 // one now available?
1310 changed = chooseNewDefaultIMELocked();
Yohei Yukawa54d512c2015-05-19 22:15:02 -07001311 } else if (!changed && isPackageModified(curIm.getPackageName())) {
1312 // Even if the current input method is still available, mCurrentSubtype could
1313 // be obsolete when the package is modified in practice.
1314 changed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001315 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001316
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001317 if (changed) {
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08001318 updateFromSettingsLocked(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 }
1320 }
1321 }
1322 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001323
Jeff Brownc28867a2013-03-26 15:42:39 -07001324 private static final class MethodCallback extends IInputSessionCallback.Stub {
Jean Chalarde0d32a62011-10-20 20:36:07 +09001325 private final InputMethodManagerService mParentIMMS;
Jeff Brownc28867a2013-03-26 15:42:39 -07001326 private final IInputMethod mMethod;
1327 private final InputChannel mChannel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001328
Jeff Brownc28867a2013-03-26 15:42:39 -07001329 MethodCallback(InputMethodManagerService imms, IInputMethod method,
1330 InputChannel channel) {
Jean Chalarde0d32a62011-10-20 20:36:07 +09001331 mParentIMMS = imms;
Jeff Brownc28867a2013-03-26 15:42:39 -07001332 mMethod = method;
1333 mChannel = channel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001335
satoke7c6998e2011-06-03 17:57:59 +09001336 @Override
Jeff Brownc28867a2013-03-26 15:42:39 -07001337 public void sessionCreated(IInputMethodSession session) {
Dianne Hackborn6b6b3fd2014-03-24 11:27:18 -07001338 long ident = Binder.clearCallingIdentity();
1339 try {
1340 mParentIMMS.onSessionCreated(mMethod, session, mChannel);
1341 } finally {
1342 Binder.restoreCallingIdentity(ident);
1343 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344 }
1345 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001346
satok01038492012-04-09 21:08:27 +09001347 private class HardKeyboardListener
Seigo Nonaka7309b122015-08-17 18:34:13 -07001348 implements WindowManagerInternal.OnHardKeyboardStatusChangeListener {
satok01038492012-04-09 21:08:27 +09001349 @Override
Michael Wright7b5a96b2014-08-09 19:28:42 -07001350 public void onHardKeyboardStatusChange(boolean available) {
1351 mHandler.sendMessage(mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED,
1352 available ? 1 : 0));
satok01038492012-04-09 21:08:27 +09001353 }
1354
Michael Wright7b5a96b2014-08-09 19:28:42 -07001355 public void handleHardKeyboardStatusChange(boolean available) {
satok01038492012-04-09 21:08:27 +09001356 if (DEBUG) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07001357 Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
satok01038492012-04-09 21:08:27 +09001358 }
1359 synchronized(mMethodMap) {
1360 if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
1361 && mSwitchingDialog.isShowing()) {
1362 mSwitchingDialogTitleView.findViewById(
1363 com.android.internal.R.id.hard_keyboard_section).setVisibility(
1364 available ? View.VISIBLE : View.GONE);
1365 }
1366 }
1367 }
1368 }
1369
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001370 public static final class Lifecycle extends SystemService {
1371 private InputMethodManagerService mService;
1372
1373 public Lifecycle(Context context) {
1374 super(context);
1375 mService = new InputMethodManagerService(context);
1376 }
1377
1378 @Override
1379 public void onStart() {
1380 LocalServices.addService(InputMethodManagerInternal.class,
Yohei Yukawafffc0e52018-09-04 13:24:00 -07001381 new LocalServiceImpl(mService));
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001382 publishBinderService(Context.INPUT_METHOD_SERVICE, mService);
1383 }
1384
1385 @Override
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001386 public void onSwitchUser(@UserIdInt int userHandle) {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001387 // Called on ActivityManager thread.
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001388 // TODO: Dispatch this to a worker thread as needed.
1389 mService.onSwitchUser(userHandle);
1390 }
1391
1392 @Override
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001393 public void onBootPhase(int phase) {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001394 // Called on ActivityManager thread.
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001395 // TODO: Dispatch this to a worker thread as needed.
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001396 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
1397 StatusBarManagerService statusBarService = (StatusBarManagerService) ServiceManager
1398 .getService(Context.STATUS_BAR_SERVICE);
1399 mService.systemRunning(statusBarService);
1400 }
1401 }
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001402
1403 @Override
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001404 public void onUnlockUser(final @UserIdInt int userHandle) {
1405 // Called on ActivityManager thread.
1406 mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_SYSTEM_UNLOCK_USER,
Fyodor Kupolov0f57cce2016-09-09 10:36:30 -07001407 userHandle /* arg1 */, 0 /* arg2 */));
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001408 }
1409 }
1410
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001411 void onUnlockUser(@UserIdInt int userId) {
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001412 synchronized(mMethodMap) {
1413 final int currentUserId = mSettings.getCurrentUserId();
1414 if (DEBUG) {
1415 Slog.d(TAG, "onUnlockUser: userId=" + userId + " curUserId=" + currentUserId);
1416 }
1417 if (userId != currentUserId) {
1418 return;
1419 }
1420 mSettings.switchCurrentUser(currentUserId, !mSystemReady);
Yohei Yukawa79247822017-01-23 15:26:15 -08001421 if (mSystemReady) {
1422 // We need to rebuild IMEs.
1423 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
1424 updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
1425 }
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001426 }
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001427 }
1428
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001429 void onSwitchUser(@UserIdInt int userId) {
1430 synchronized (mMethodMap) {
1431 switchUserLocked(userId);
1432 }
1433 }
1434
Seigo Nonaka7309b122015-08-17 18:34:13 -07001435 public InputMethodManagerService(Context context) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001436 mIPackageManager = AppGlobals.getPackageManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001437 mContext = context;
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -08001438 mRes = context.getResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439 mHandler = new Handler(this);
Yohei Yukawa81482972015-06-04 00:58:59 -07001440 // Note: SettingsObserver doesn't register observers in its constructor.
1441 mSettingsObserver = new SettingsObserver(mHandler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 mIWindowManager = IWindowManager.Stub.asInterface(
1443 ServiceManager.getService(Context.WINDOW_SERVICE));
Seigo Nonaka7309b122015-08-17 18:34:13 -07001444 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
Yohei Yukawab4f328a2019-05-02 08:41:27 -07001445 mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
lumark9a72d222019-03-30 18:31:45 +08001446 mImeDisplayValidator = displayId -> mWindowManagerInternal.shouldShowIme(displayId);
Mita Yuned218c72012-12-06 17:18:25 -08001447 mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
satoke7c6998e2011-06-03 17:57:59 +09001448 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 public void executeMessage(Message msg) {
1450 handleMessage(msg);
1451 }
Mita Yuned218c72012-12-06 17:18:25 -08001452 }, true /*asyncHandler*/);
Yohei Yukawad34e1482016-02-11 08:03:52 -08001453 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001454 mUserManager = mContext.getSystemService(UserManager.class);
Yohei Yukawa42081402019-01-15 09:57:50 -08001455 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
satok01038492012-04-09 21:08:27 +09001456 mHardKeyboardListener = new HardKeyboardListener();
Dianne Hackborn119bbc32013-03-22 17:27:25 -07001457 mHasFeature = context.getPackageManager().hasSystemFeature(
1458 PackageManager.FEATURE_INPUT_METHODS);
Jason Monk3e189872016-01-12 09:10:34 -05001459 mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
Tarandeep Singheadb1392018-11-09 18:15:57 +01001460 mIsLowRam = ActivityManager.isLowRamDeviceStatic();
satok7cfc0ed2011-06-20 21:29:36 +09001461
Chris Wren1ce4b6d2015-06-11 10:19:43 -04001462 Bundle extras = new Bundle();
1463 extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001464 @ColorInt final int accentColor = mContext.getColor(
1465 com.android.internal.R.color.system_notification_accent_color);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001466 mImeSwitcherNotification =
1467 new Notification.Builder(mContext, SystemNotificationChannels.VIRTUAL_KEYBOARD)
1468 .setSmallIcon(com.android.internal.R.drawable.ic_notification_ime_default)
1469 .setWhen(0)
1470 .setOngoing(true)
1471 .addExtras(extras)
1472 .setCategory(Notification.CATEGORY_SYSTEM)
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001473 .setColor(accentColor);
Daniel Sandler590d5152012-06-14 16:10:13 -04001474
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001475 Intent intent = new Intent(ACTION_SHOW_INPUT_METHOD_PICKER)
1476 .setPackage(mContext.getPackageName());
satok683e2382011-07-12 08:28:52 +09001477 mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
satokb858c732011-07-22 19:54:34 +09001478
1479 mShowOngoingImeSwitcherForPhones = false;
satok7cfc0ed2011-06-20 21:29:36 +09001480
satok7cfc0ed2011-06-20 21:29:36 +09001481 mNotificationShown = false;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001482 int userId = 0;
1483 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001484 userId = ActivityManager.getService().getCurrentUser().id;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001485 } catch (RemoteException e) {
1486 Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
1487 }
satok913a8922010-08-26 21:53:41 +09001488
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08001489 mLastSwitchUserId = userId;
1490
satokd87c2592010-09-29 11:52:06 +09001491 // mSettings should be created before buildInputMethodListLocked
satokdf31ae62011-01-15 06:19:44 +09001492 mSettings = new InputMethodSettings(
Yohei Yukawaf9277532019-01-25 02:47:32 -08001493 mRes, context.getContentResolver(), mMethodMap, userId, !mSystemReady);
Svet Ganovadc1cf42015-06-15 16:36:24 -07001494
Kenny Guy2a764942014-04-02 13:29:20 +01001495 updateCurrentProfileIds();
Yohei Yukawab557d572018-12-29 21:26:26 -08001496 AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
Yohei Yukawa79247822017-01-23 15:26:15 -08001497 mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
1498 mSettings, context);
satok5b927c432012-05-01 20:09:34 +09001499 }
1500
satok5b927c432012-05-01 20:09:34 +09001501 private void resetDefaultImeLocked(Context context) {
1502 // Do not reset the default (current) IME when it is a 3rd-party IME
Yohei Yukawafd70fe82018-04-08 12:19:56 -07001503 if (mCurMethodId != null && !mMethodMap.get(mCurMethodId).isSystem()) {
satok5b927c432012-05-01 20:09:34 +09001504 return;
1505 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001506 final List<InputMethodInfo> suitableImes = InputMethodUtils.getDefaultEnabledImes(
Yohei Yukawaaf5cee82017-01-23 16:17:11 -08001507 context, mSettings.getEnabledInputMethodListLocked());
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001508 if (suitableImes.isEmpty()) {
1509 Slog.i(TAG, "No default found");
1510 return;
satok5b927c432012-05-01 20:09:34 +09001511 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001512 final InputMethodInfo defIm = suitableImes.get(0);
Yohei Yukawad0332832017-02-01 13:59:43 -08001513 if (DEBUG) {
1514 Slog.i(TAG, "Default found, using " + defIm.getId());
1515 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001516 setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
satok5b927c432012-05-01 20:09:34 +09001517 }
1518
Andreas Gampea36dc622018-02-05 17:19:22 -08001519 @GuardedBy("mMethodMap")
Satoshi Kataoka5ade83b2012-09-26 22:59:41 +09001520 private void switchUserLocked(int newUserId) {
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001521 if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
1522 + " currentUserId=" + mSettings.getCurrentUserId());
1523
Yohei Yukawa81482972015-06-04 00:58:59 -07001524 // ContentObserver should be registered again when the user is changed
1525 mSettingsObserver.registerContentObserverLocked(newUserId);
Yohei Yukawa68645a62016-02-17 07:54:20 -08001526
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001527 // If the system is not ready or the device is not yed unlocked by the user, then we use
1528 // copy-on-write settings.
1529 final boolean useCopyOnWriteSettings =
Yohei Yukawa42081402019-01-15 09:57:50 -08001530 !mSystemReady || !mUserManagerInternal.isUserUnlockingOrUnlocked(newUserId);
Yohei Yukawa68645a62016-02-17 07:54:20 -08001531 mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
Kenny Guy2a764942014-04-02 13:29:20 +01001532 updateCurrentProfileIds();
Yohei Yukawab557d572018-12-29 21:26:26 -08001533 // Additional subtypes should be reset when the user is changed
1534 AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, newUserId);
Satoshi Kataoka7f7535f2013-02-18 12:54:16 +09001535 final String defaultImiId = mSettings.getSelectedInputMethod();
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001536
1537 if (DEBUG) Slog.d(TAG, "Switching user stage 2/3. newUserId=" + newUserId
1538 + " defaultImiId=" + defaultImiId);
1539
Satoshi Kataoka7c4a2a12013-02-25 15:25:43 +09001540 // For secondary users, the list of enabled IMEs may not have been updated since the
1541 // callbacks to PackageMonitor are ignored for the secondary user. Here, defaultImiId may
1542 // not be empty even if the IME has been uninstalled by the primary user.
1543 // Even in such cases, IMMS works fine because it will find the most applicable
1544 // IME for that user.
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001545 final boolean initialUserSwitch = TextUtils.isEmpty(defaultImiId);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001546 mLastSystemLocales = mRes.getConfiguration().getLocales();
1547
1548 // TODO: Is it really possible that switchUserLocked() happens before system ready?
1549 if (mSystemReady) {
1550 hideCurrentInputLocked(0, null);
Yohei Yukawab7526452018-10-21 20:15:17 -07001551 resetCurrentMethodAndClient(UnbindReason.SWITCH_USER);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001552 buildInputMethodListLocked(initialUserSwitch);
1553 if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) {
1554 // This is the first time of the user switch and
1555 // set the current ime to the proper one.
1556 resetDefaultImeLocked(mContext);
1557 }
1558 updateFromSettingsLocked(true);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001559 }
1560
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001561 if (initialUserSwitch) {
Yohei Yukawa094c71f2015-06-20 00:41:31 -07001562 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
1563 mSettings.getEnabledInputMethodListLocked(), newUserId,
1564 mContext.getBasePackageName());
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001565 }
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001566
1567 if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId
1568 + " selectedIme=" + mSettings.getSelectedInputMethod());
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08001569
1570 mLastSwitchUserId = newUserId;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001571 }
1572
Kenny Guy2a764942014-04-02 13:29:20 +01001573 void updateCurrentProfileIds() {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -07001574 mSettings.setCurrentProfileIds(
1575 mUserManager.getProfileIdsWithDisabled(mSettings.getCurrentUserId()));
Amith Yamasani734983f2014-03-04 16:48:05 -08001576 }
1577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 @Override
1579 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1580 throws RemoteException {
1581 try {
1582 return super.onTransact(code, data, reply, flags);
1583 } catch (RuntimeException e) {
1584 // The input method manager only throws security exceptions, so let's
1585 // log all others.
1586 if (!(e instanceof SecurityException)) {
Dianne Hackborn164371f2013-10-01 19:10:13 -07001587 Slog.wtf(TAG, "Input Method Manager Crash", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 }
1589 throw e;
1590 }
1591 }
1592
Svetoslav Ganova0027152013-06-25 14:59:53 -07001593 public void systemRunning(StatusBarManagerService statusBar) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001594 synchronized (mMethodMap) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001595 if (DEBUG) {
1596 Slog.d(TAG, "--- systemReady");
1597 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001598 if (!mSystemReady) {
1599 mSystemReady = true;
Yohei Yukawa79247822017-01-23 15:26:15 -08001600 mLastSystemLocales = mRes.getConfiguration().getLocales();
Yohei Yukawa68645a62016-02-17 07:54:20 -08001601 final int currentUserId = mSettings.getCurrentUserId();
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001602 mSettings.switchCurrentUser(currentUserId,
Yohei Yukawa42081402019-01-15 09:57:50 -08001603 !mUserManagerInternal.isUserUnlockingOrUnlocked(currentUserId));
Yohei Yukawad34e1482016-02-11 08:03:52 -08001604 mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
1605 mNotificationManager = mContext.getSystemService(NotificationManager.class);
Dianne Hackborn661cd522011-08-22 00:26:20 -07001606 mStatusBar = statusBar;
Griff Hazen6090c262016-03-25 08:11:24 -07001607 if (mStatusBar != null) {
1608 mStatusBar.setIconVisibility(mSlotIme, false);
1609 }
Yohei Yukawa849443c2019-01-21 09:02:25 -08001610 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
satokb858c732011-07-22 19:54:34 +09001611 mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
1612 com.android.internal.R.bool.show_ongoing_ime_switcher);
satok01038492012-04-09 21:08:27 +09001613 if (mShowOngoingImeSwitcherForPhones) {
Seigo Nonaka7309b122015-08-17 18:34:13 -07001614 mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
satok01038492012-04-09 21:08:27 +09001615 mHardKeyboardListener);
1616 }
Yohei Yukawa79247822017-01-23 15:26:15 -08001617
1618 mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
1619 mSettingsObserver.registerContentObserverLocked(currentUserId);
1620
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001621 final IntentFilter broadcastFilterForSystemUser = new IntentFilter();
1622 broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_ADDED);
1623 broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_REMOVED);
1624 broadcastFilterForSystemUser.addAction(Intent.ACTION_LOCALE_CHANGED);
1625 broadcastFilterForSystemUser.addAction(ACTION_SHOW_INPUT_METHOD_PICKER);
1626 mContext.registerReceiver(new ImmsBroadcastReceiverForSystemUser(),
1627 broadcastFilterForSystemUser);
1628
1629 final IntentFilter broadcastFilterForAllUsers = new IntentFilter();
1630 broadcastFilterForAllUsers.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
1631 mContext.registerReceiverAsUser(new ImmsBroadcastReceiverForAllUsers(),
1632 UserHandle.ALL, broadcastFilterForAllUsers, null, null);
Yohei Yukawa79247822017-01-23 15:26:15 -08001633
Yohei Yukawa1f9a3cb2017-10-26 15:00:59 -07001634 final String defaultImiId = mSettings.getSelectedInputMethod();
1635 final boolean imeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
1636 buildInputMethodListLocked(!imeSelectedOnBoot /* resetDefaultEnabledIme */);
Yohei Yukawa79247822017-01-23 15:26:15 -08001637 updateFromSettingsLocked(true);
1638 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
1639 mSettings.getEnabledInputMethodListLocked(), currentUserId,
1640 mContext.getBasePackageName());
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001641 }
1642 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001644
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001645 // ---------------------------------------------------------------------------------------
1646 // Check whether or not this is a valid IPC. Assumes an IPC is valid when either
1647 // 1) it comes from the system process
1648 // 2) the calling process' user id is identical to the current user id IMMS thinks.
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001649 @GuardedBy("mMethodMap")
Yohei Yukawa46d74762019-01-22 10:17:22 -08001650 private boolean calledFromValidUserLocked() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001651 final int uid = Binder.getCallingUid();
1652 final int userId = UserHandle.getUserId(uid);
1653 if (DEBUG) {
1654 Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
1655 + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
1656 + " calling userId = " + userId + ", foreground user id = "
Satoshi Kataoka87c29142013-07-31 23:11:54 +09001657 + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid()
1658 + InputMethodUtils.getApiCallStack());
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001659 }
Yohei Yukawaa878b952019-01-10 19:36:24 -08001660 if (uid == Process.SYSTEM_UID) {
1661 return true;
1662 }
1663 if (userId == mSettings.getCurrentUserId()) {
1664 return true;
1665 }
Satoshi Kataoka135e5fb2012-09-28 18:25:06 +09001666
1667 // Caveat: A process which has INTERACT_ACROSS_USERS_FULL gets results for the
1668 // foreground user, not for the user of that process. Accordingly InputMethodManagerService
1669 // must not manage background users' states in any functions.
1670 // Note that privacy-sensitive IPCs, such as setInputMethod, are still securely guarded
1671 // by a token.
1672 if (mContext.checkCallingOrSelfPermission(
1673 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1674 == PackageManager.PERMISSION_GRANTED) {
1675 if (DEBUG) {
1676 Slog.d(TAG, "--- Access granted because the calling process has "
1677 + "the INTERACT_ACROSS_USERS_FULL permission");
1678 }
1679 return true;
1680 }
Yohei Yukawad0332832017-02-01 13:59:43 -08001681 // TODO(b/34886274): The semantics of this verification is actually not well-defined.
Seigo Nonakae27dc2b2015-08-14 18:21:27 -07001682 Slog.w(TAG, "--- IPC called from background users. Ignore. callers="
1683 + Debug.getCallers(10));
Satoshi Kataoka135e5fb2012-09-28 18:25:06 +09001684 return false;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001685 }
1686
Yohei Yukawa22c97be2014-06-04 19:43:36 +09001687
1688 /**
1689 * Returns true iff the caller is identified to be the current input method with the token.
1690 * @param token The window token given to the input method when it was started.
1691 * @return true if and only if non-null valid token is specified.
1692 */
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08001693 @GuardedBy("mMethodMap")
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08001694 private boolean calledWithValidTokenLocked(@NonNull IBinder token) {
1695 if (token == null) {
1696 throw new InvalidParameterException("token must not be null.");
Yohei Yukawad0332832017-02-01 13:59:43 -08001697 }
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08001698 if (token != mCurToken) {
Yohei Yukawad0332832017-02-01 13:59:43 -08001699 Slog.e(TAG, "Ignoring " + Debug.getCaller() + " due to an invalid token."
1700 + " uid:" + Binder.getCallingUid() + " token:" + token);
Yohei Yukawa22c97be2014-06-04 19:43:36 +09001701 return false;
1702 }
1703 return true;
1704 }
1705
Yohei Yukawaf80087c2018-05-21 09:47:53 -07001706 @GuardedBy("mMethodMap")
1707 private boolean bindCurrentInputMethodServiceLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001708 Intent service, ServiceConnection conn, int flags) {
1709 if (service == null || conn == null) {
1710 Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn);
1711 return false;
1712 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08001713 return mContext.bindServiceAsUser(service, conn, flags,
1714 new UserHandle(mSettings.getCurrentUserId()));
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001715 }
1716
satoke7c6998e2011-06-03 17:57:59 +09001717 @Override
Yohei Yukawad20eef82019-02-05 10:45:32 -08001718 public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
1719 if (UserHandle.getCallingUserId() != userId) {
1720 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
1721 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001722 synchronized (mMethodMap) {
Yohei Yukawad20eef82019-02-05 10:45:32 -08001723 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001724 mSettings.getCurrentUserId(), null);
1725 if (resolvedUserIds.length != 1) {
1726 return Collections.emptyList();
1727 }
1728 final long ident = Binder.clearCallingIdentity();
1729 try {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08001730 return getInputMethodListLocked(resolvedUserIds[0]);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001731 } finally {
1732 Binder.restoreCallingIdentity(ident);
Tarandeep Singh89a6c482017-11-21 14:26:11 -08001733 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 }
1735 }
1736
satoke7c6998e2011-06-03 17:57:59 +09001737 @Override
Yohei Yukawa1fb13c52019-02-05 07:55:28 -08001738 public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
1739 if (UserHandle.getCallingUserId() != userId) {
1740 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
1741 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 synchronized (mMethodMap) {
Yohei Yukawa1fb13c52019-02-05 07:55:28 -08001743 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001744 mSettings.getCurrentUserId(), null);
1745 if (resolvedUserIds.length != 1) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001746 return Collections.emptyList();
1747 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001748 final long ident = Binder.clearCallingIdentity();
1749 try {
1750 return getEnabledInputMethodListLocked(resolvedUserIds[0]);
1751 } finally {
1752 Binder.restoreCallingIdentity(ident);
1753 }
1754 }
1755 }
1756
1757 @GuardedBy("mMethodMap")
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08001758 private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001759 final ArrayList<InputMethodInfo> methodList;
1760 if (userId == mSettings.getCurrentUserId()) {
1761 // Create a copy.
1762 methodList = new ArrayList<>(mMethodList);
1763 } else {
1764 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1765 methodList = new ArrayList<>();
1766 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1767 new ArrayMap<>();
1768 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1769 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1770 methodList);
1771 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001772 return methodList;
1773 }
1774
1775 @GuardedBy("mMethodMap")
1776 private List<InputMethodInfo> getEnabledInputMethodListLocked(@UserIdInt int userId) {
1777 if (userId == mSettings.getCurrentUserId()) {
satokd87c2592010-09-29 11:52:06 +09001778 return mSettings.getEnabledInputMethodListLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001780 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1781 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
1782 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1783 new ArrayMap<>();
1784 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1785 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1786 methodList);
1787 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
Yohei Yukawaf9277532019-01-25 02:47:32 -08001788 mContext.getContentResolver(), methodMap, userId, true);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001789 return settings.getEnabledInputMethodListLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 }
1791
Adam Hebc67f2e2019-11-13 14:34:56 -08001792 @GuardedBy("mMethodMap")
1793 private void onCreateInlineSuggestionsRequestLocked(ComponentName componentName,
1794 AutofillId autofillId, IInlineSuggestionsRequestCallback callback) {
Adam He7bc8f602019-12-12 17:00:34 -08001795
1796 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
1797 try {
1798 if (imi != null && imi.isInlineSuggestionsEnabled() && mCurMethod != null) {
1799 executeOrSendMessage(mCurMethod,
1800 mCaller.obtainMessageOOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod,
1801 componentName, autofillId, callback));
1802 } else {
1803 callback.onInlineSuggestionsUnsupported();
1804 }
1805 } catch (RemoteException e) {
1806 Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
Adam Hebc67f2e2019-11-13 14:34:56 -08001807 }
1808 }
1809
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001810 /**
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001811 * @param imiId if null, returns enabled subtypes for the current imi
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001812 * @return enabled subtypes of the specified imi
1813 */
satoke7c6998e2011-06-03 17:57:59 +09001814 @Override
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001815 public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
satok16331c82010-12-20 23:48:46 +09001816 boolean allowsImplicitlySelectedSubtypes) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001817 final int callingUserId = UserHandle.getCallingUserId();
satok67ddf9c2010-11-17 09:45:54 +09001818 synchronized (mMethodMap) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001819 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
1820 mSettings.getCurrentUserId(), null);
1821 if (resolvedUserIds.length != 1) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001822 return Collections.emptyList();
1823 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001824 final long ident = Binder.clearCallingIdentity();
1825 try {
1826 return getEnabledInputMethodSubtypeListLocked(imiId,
1827 allowsImplicitlySelectedSubtypes, resolvedUserIds[0]);
1828 } finally {
1829 Binder.restoreCallingIdentity(ident);
1830 }
1831 }
1832 }
1833
1834 @GuardedBy("mMethodMap")
1835 private List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(String imiId,
1836 boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) {
1837 if (userId == mSettings.getCurrentUserId()) {
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001838 final InputMethodInfo imi;
1839 if (imiId == null && mCurMethodId != null) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001840 imi = mMethodMap.get(mCurMethodId);
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001841 } else {
1842 imi = mMethodMap.get(imiId);
1843 }
1844 if (imi == null) {
Yohei Yukawab0377bb2015-08-10 21:06:30 -07001845 return Collections.emptyList();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001846 }
1847 return mSettings.getEnabledInputMethodSubtypeListLocked(
1848 mContext, imi, allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +09001849 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001850 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1851 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
1852 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1853 new ArrayMap<>();
1854 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1855 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1856 methodList);
1857 final InputMethodInfo imi = methodMap.get(imiId);
1858 if (imi == null) {
1859 return Collections.emptyList();
1860 }
1861 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
Yohei Yukawaf9277532019-01-25 02:47:32 -08001862 mContext.getContentResolver(), methodMap, userId, true);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001863 return settings.getEnabledInputMethodSubtypeListLocked(
1864 mContext, imi, allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +09001865 }
1866
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001867 /**
1868 * Called by each application process as a preparation to start interacting with
1869 * {@link InputMethodManagerService}.
1870 *
1871 * <p>As a general principle, IPCs from the application process that take
Yohei Yukawa499e3f72018-10-21 20:15:11 -07001872 * {@link IInputMethodClient} will be rejected without this step.</p>
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001873 *
1874 * @param client {@link android.os.Binder} proxy that is associated with the singleton instance
1875 * of {@link android.view.inputmethod.InputMethodManager} that runs on the client
1876 * process
1877 * @param inputContext communication channel for the dummy
1878 * {@link android.view.inputmethod.InputConnection}
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001879 * @param selfReportedDisplayId self-reported display ID to which the client is associated.
1880 * Whether the client is still allowed to access to this display
1881 * or not needs to be evaluated every time the client interacts
1882 * with the display
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001883 */
1884 @Override
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001885 public void addClient(IInputMethodClient client, IInputContext inputContext,
1886 int selfReportedDisplayId) {
Yohei Yukawacb768bc2018-10-24 16:05:09 -07001887 // Here there are two scenarios where this method is called:
1888 // A. IMM is being instantiated in a different process and this is an IPC from that process
1889 // B. IMM is being instantiated in the same process but Binder.clearCallingIdentity() is
1890 // called in the caller side if necessary.
1891 // In either case the following UID/PID should be the ones where InputMethodManager is
1892 // actually running.
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001893 final int callerUid = Binder.getCallingUid();
1894 final int callerPid = Binder.getCallingPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001895 synchronized (mMethodMap) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001896 // TODO: Optimize this linear search.
Yohei Yukawaac9311e2018-11-20 19:25:23 -08001897 final int numClients = mClients.size();
1898 for (int i = 0; i < numClients; ++i) {
1899 final ClientState state = mClients.valueAt(i);
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001900 if (state.uid == callerUid && state.pid == callerPid
1901 && state.selfReportedDisplayId == selfReportedDisplayId) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001902 throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
Yohei Yukawacb768bc2018-10-24 16:05:09 -07001903 + "/displayId=" + selfReportedDisplayId + " is already registered.");
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001904 }
1905 }
1906 final ClientDeathRecipient deathRecipient = new ClientDeathRecipient(this, client);
1907 try {
1908 client.asBinder().linkToDeath(deathRecipient, 0);
1909 } catch (RemoteException e) {
1910 throw new IllegalStateException(e);
1911 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001912 // We cannot fully avoid race conditions where the client UID already lost the access to
1913 // the given self-reported display ID, even if the client is not maliciously reporting
1914 // a fake display ID. Unconditionally returning SecurityException just because the
1915 // client doesn't pass display ID verification can cause many test failures hence not an
1916 // option right now. At the same time
1917 // context.getSystemService(InputMethodManager.class)
1918 // is expected to return a valid non-null instance at any time if we do not choose to
1919 // have the client crash. Thus we do not verify the display ID at all here. Instead we
1920 // later check the display ID every time the client needs to interact with the specified
1921 // display.
1922 mClients.put(client.asBinder(), new ClientState(client, inputContext, callerUid,
1923 callerPid, selfReportedDisplayId, deathRecipient));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 }
1925 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001926
Yohei Yukawae24ed792018-08-28 19:10:32 -07001927 void removeClient(IInputMethodClient client) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001928 synchronized (mMethodMap) {
Jeff Brownc28867a2013-03-26 15:42:39 -07001929 ClientState cs = mClients.remove(client.asBinder());
1930 if (cs != null) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001931 client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
Jeff Brownc28867a2013-03-26 15:42:39 -07001932 clearClientSessionLocked(cs);
Yohei Yukawab4f328a2019-05-02 08:41:27 -07001933
1934 final int numItems = mActivityViewDisplayIdToParentMap.size();
1935 for (int i = numItems - 1; i >= 0; --i) {
1936 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.valueAt(i);
1937 if (info.mParentClient == cs) {
1938 mActivityViewDisplayIdToParentMap.removeAt(i);
1939 }
1940 }
1941
Yohei Yukawa072b1b52015-11-18 15:54:34 -08001942 if (mCurClient == cs) {
Tarandeep Singh93c00cea2018-02-16 14:31:17 -08001943 if (mBoundToMethod) {
1944 mBoundToMethod = false;
1945 if (mCurMethod != null) {
1946 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
1947 MSG_UNBIND_INPUT, mCurMethod));
1948 }
1949 }
Yohei Yukawa072b1b52015-11-18 15:54:34 -08001950 mCurClient = null;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07001951 mCurActivityViewToScreenMatrix = null;
Yohei Yukawa072b1b52015-11-18 15:54:34 -08001952 }
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08001953 if (mCurFocusedWindowClient == cs) {
1954 mCurFocusedWindowClient = null;
1955 }
Jeff Brownc28867a2013-03-26 15:42:39 -07001956 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001957 }
1958 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001959
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001960 void executeOrSendMessage(IInterface target, Message msg) {
1961 if (target.asBinder() instanceof Binder) {
1962 mCaller.sendMessage(msg);
1963 } else {
1964 handleMessage(msg);
1965 msg.recycle();
1966 }
1967 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001968
Yohei Yukawa4afd9332018-10-21 10:43:53 -07001969 void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 if (mCurClient != null) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001971 if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001972 + mCurClient.client.asBinder());
1973 if (mBoundToMethod) {
1974 mBoundToMethod = false;
1975 if (mCurMethod != null) {
1976 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
1977 MSG_UNBIND_INPUT, mCurMethod));
1978 }
1979 }
Dianne Hackborna6e41342012-05-22 16:30:34 -07001980
Yohei Yukawa2bc66172017-02-08 11:13:25 -08001981 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
1982 MSG_SET_ACTIVE, 0, 0, mCurClient));
Yohei Yukawa33e81792015-11-17 21:14:42 -08001983 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
1984 MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001985 mCurClient.sessionRequested = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001986 mCurClient = null;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07001987 mCurActivityViewToScreenMatrix = null;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001988
The Android Open Source Project10592532009-03-18 17:39:46 -07001989 hideInputMethodMenuLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 }
1991 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001992
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993 private int getImeShowFlags() {
1994 int flags = 0;
1995 if (mShowForced) {
1996 flags |= InputMethod.SHOW_FORCED
1997 | InputMethod.SHOW_EXPLICIT;
1998 } else if (mShowExplicitlyRequested) {
1999 flags |= InputMethod.SHOW_EXPLICIT;
2000 }
2001 return flags;
2002 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 private int getAppShowFlags() {
2005 int flags = 0;
2006 if (mShowForced) {
2007 flags |= InputMethodManager.SHOW_FORCED;
2008 } else if (!mShowExplicitlyRequested) {
2009 flags |= InputMethodManager.SHOW_IMPLICIT;
2010 }
2011 return flags;
2012 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002013
Andreas Gampea36dc622018-02-05 17:19:22 -08002014 @GuardedBy("mMethodMap")
Yohei Yukawa2553e482017-12-15 15:47:33 -08002015 @NonNull
Yohei Yukawadc66e522018-10-21 10:43:14 -07002016 InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002017 if (!mBoundToMethod) {
2018 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
2019 MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
2020 mBoundToMethod = true;
2021 }
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002022
2023 final Binder startInputToken = new Binder();
Yohei Yukawa7979e1a2019-02-12 02:01:10 -08002024 final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), mCurToken,
2025 mCurTokenDisplayId, mCurId, startInputReason, !initial,
2026 UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId,
2027 mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, mCurSeq);
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002028 mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
Yohei Yukawa357b2f62017-02-14 09:40:03 -08002029 mStartInputHistory.addEntry(info);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002030
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002031 final SessionState session = mCurClient.curSession;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002032 executeOrSendMessage(session.method, mCaller.obtainMessageIIOOOO(
Yohei Yukawaf7526b52017-02-11 20:57:10 -08002033 MSG_START_INPUT, mCurInputContextMissingMethods, initial ? 0 : 1 /* restarting */,
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002034 startInputToken, session, mCurInputContext, mCurAttribute));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002035 if (mShowRequested) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002036 if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
The Android Open Source Project4df24232009-03-05 14:34:35 -08002037 showCurrentInputLocked(getAppShowFlags(), null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002038 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002039 return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
2040 session.session, (session.channel != null ? session.channel.dup() : null),
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002041 mCurId, mCurSeq, mCurActivityViewToScreenMatrix);
2042 }
2043
2044 @Nullable
2045 private Matrix getActivityViewToScreenMatrixLocked(int clientDisplayId, int imeDisplayId) {
2046 if (clientDisplayId == imeDisplayId) {
2047 return null;
2048 }
2049 int displayId = clientDisplayId;
2050 Matrix matrix = null;
2051 while (true) {
2052 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(displayId);
2053 if (info == null) {
2054 return null;
2055 }
2056 if (matrix == null) {
2057 matrix = new Matrix(info.mMatrix);
2058 } else {
2059 matrix.postConcat(info.mMatrix);
2060 }
2061 if (info.mParentClient.selfReportedDisplayId == imeDisplayId) {
2062 return matrix;
2063 }
2064 displayId = info.mParentClient.selfReportedDisplayId;
2065 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002067
Andreas Gampea36dc622018-02-05 17:19:22 -08002068 @GuardedBy("mMethodMap")
Yohei Yukawa2553e482017-12-15 15:47:33 -08002069 @NonNull
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002070 InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002071 @MissingMethodFlags int missingMethods, @NonNull EditorInfo attribute,
2072 @StartInputFlags int startInputFlags, @StartInputReason int startInputReason) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08002073 // If no method is currently selected, do nothing.
2074 if (mCurMethodId == null) {
Yohei Yukawa2553e482017-12-15 15:47:33 -08002075 return InputBindResult.NO_IME;
Dianne Hackborn7663d802012-02-24 13:08:49 -08002076 }
2077
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002078 if (!mSystemReady) {
2079 // If the system is not yet ready, we shouldn't be running third
2080 // party code.
2081 return new InputBindResult(
2082 InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002083 null, null, mCurMethodId, mCurSeq, null);
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002084 }
2085
Yohei Yukawad57ba672015-06-08 16:39:46 -07002086 if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
2087 attribute.packageName)) {
2088 Slog.e(TAG, "Rejecting this client as it reported an invalid package name."
2089 + " uid=" + cs.uid + " package=" + attribute.packageName);
Yohei Yukawa2553e482017-12-15 15:47:33 -08002090 return InputBindResult.INVALID_PACKAGE_NAME;
Yohei Yukawa0f3ad12015-04-06 16:48:24 -07002091 }
2092
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002093 if (!mWindowManagerInternal.isUidAllowedOnDisplay(cs.selfReportedDisplayId, cs.uid)) {
2094 // Wait, the client no longer has access to the display.
2095 return InputBindResult.INVALID_DISPLAY_ID;
2096 }
lumarkef1965b2018-09-12 17:42:53 +08002097 // Compute the final shown display ID with validated cs.selfReportedDisplayId for this
2098 // session & other conditions.
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08002099 final int displayIdToShowIme = computeImeDisplayIdForTarget(cs.selfReportedDisplayId,
2100 mImeDisplayValidator);
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002102 if (mCurClient != cs) {
John Spurlocke0980502013-10-25 11:59:29 -04002103 // Was the keyguard locked when switching over to the new client?
2104 mCurClientInKeyguard = isKeyguardLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002105 // If the client is changing, we need to switch over to the new
2106 // one.
Yohei Yukawab7526452018-10-21 20:15:17 -07002107 unbindCurrentClientLocked(UnbindReason.SWITCH_CLIENT);
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002108 if (DEBUG) Slog.v(TAG, "switching to client: client="
John Spurlocke0980502013-10-25 11:59:29 -04002109 + cs.client.asBinder() + " keyguard=" + mCurClientInKeyguard);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002110
2111 // If the screen is on, inform the new client it is active
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07002112 if (mIsInteractive) {
tiansiming [田思明]e102c972018-04-17 18:15:33 +08002113 executeOrSendMessage(cs.client, mCaller.obtainMessageIO(MSG_SET_ACTIVE, 1, cs));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002114 }
2115 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002117 // Bump up the sequence for this client and attach it.
2118 mCurSeq++;
2119 if (mCurSeq <= 0) mCurSeq = 1;
2120 mCurClient = cs;
2121 mCurInputContext = inputContext;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002122 mCurActivityViewToScreenMatrix =
2123 getActivityViewToScreenMatrixLocked(cs.selfReportedDisplayId, displayIdToShowIme);
2124 if (cs.selfReportedDisplayId != displayIdToShowIme
2125 && mCurActivityViewToScreenMatrix == null) {
Yohei Yukawa3d2cc0f2019-04-25 18:32:15 -07002126 // CursorAnchorInfo API does not work as-is for cross-display scenario. Pretend that
2127 // InputConnection#requestCursorUpdates() is not implemented in the application so that
2128 // IMEs will always receive false from this API.
2129 missingMethods |= MissingMethodFlags.REQUEST_CURSOR_UPDATES;
2130 }
Yohei Yukawa19a80a12016-03-14 22:57:37 -07002131 mCurInputContextMissingMethods = missingMethods;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 mCurAttribute = attribute;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002134 // Check if the input method is changing.
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002135 // We expect the caller has already verified that the client is allowed to access this
2136 // display ID.
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002137 if (mCurId != null && mCurId.equals(mCurMethodId)
2138 && displayIdToShowIme == mCurTokenDisplayId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002139 if (cs.curSession != null) {
2140 // Fast case: if we are already connected to the input method,
2141 // then just return it.
Yohei Yukawa87ca8402017-02-07 00:13:14 -08002142 return attachNewInputLocked(startInputReason,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002143 (startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002144 }
2145 if (mHaveConnection) {
2146 if (mCurMethod != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002147 // Return to client, and we will get back with it when
2148 // we have had a session made for it.
Jeff Brownc28867a2013-03-26 15:42:39 -07002149 requestClientSessionLocked(cs);
Yohei Yukawa2553e482017-12-15 15:47:33 -08002150 return new InputBindResult(
2151 InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002152 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002153 } else if (SystemClock.uptimeMillis()
2154 < (mLastBindTime+TIME_TO_RECONNECT)) {
2155 // In this case we have connected to the service, but
2156 // don't yet have its interface. If it hasn't been too
2157 // long since we did the connection, we'll return to
2158 // the client and wait to get the service interface so
2159 // we can report back. If it has been too long, we want
2160 // to fall through so we can try a disconnect/reconnect
2161 // to see if we can get back in touch with the service.
Yohei Yukawa2553e482017-12-15 15:47:33 -08002162 return new InputBindResult(
2163 InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002164 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002165 } else {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002166 EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
2167 mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002168 }
2169 }
2170 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002172 InputMethodInfo info = mMethodMap.get(mCurMethodId);
2173 if (info == null) {
2174 throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
2175 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002176
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002177 unbindCurrentMethodLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002179 mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
2180 mCurIntent.setComponent(info.getComponent());
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07002181 mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
2182 com.android.internal.R.string.input_method_binding_label);
2183 mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
2184 mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002185
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002186 if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002187 mLastBindTime = SystemClock.uptimeMillis();
2188 mHaveConnection = true;
2189 mCurId = info.getId();
2190 mCurToken = new Binder();
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002191 mCurTokenDisplayId = displayIdToShowIme;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002192 try {
lumark90120a82018-08-15 00:33:03 +08002193 if (DEBUG) {
2194 Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
2195 + mCurTokenDisplayId);
2196 }
Yohei Yukawa6e875592019-01-28 00:49:30 -08002197 mIWindowManager.addWindowToken(mCurToken, LayoutParams.TYPE_INPUT_METHOD,
2198 mCurTokenDisplayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002199 } catch (RemoteException e) {
2200 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002201 return new InputBindResult(
2202 InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002203 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002204 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002205 mCurIntent = null;
2206 Slog.w(TAG, "Failure connecting to input method service: " + mCurIntent);
2207 return InputBindResult.IME_NOT_CONNECTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002208 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002209
lumarkef1965b2018-09-12 17:42:53 +08002210 @FunctionalInterface
2211 interface ImeDisplayValidator {
2212 boolean displayCanShowIme(int displayId);
2213 }
2214
2215 /**
2216 * Find the display where the IME should be shown.
2217 *
2218 * @param displayId the ID of the display where the IME client target is.
lumarkef1965b2018-09-12 17:42:53 +08002219 * @param checker instance of {@link ImeDisplayValidator} which is used for
2220 * checking display config to adjust the final target display.
2221 * @return The ID of the display where the IME should be shown.
2222 */
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08002223 static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
lumarkef1965b2018-09-12 17:42:53 +08002224 if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
lumark7570cac2019-03-07 22:14:38 +08002225 return FALLBACK_DISPLAY_ID;
lumarkef1965b2018-09-12 17:42:53 +08002226 }
lumark9a72d222019-03-30 18:31:45 +08002227
2228 // Show IME window on fallback display when the display doesn't support system decorations
2229 // or the display is virtual and isn't owned by system for security concern.
lumark7570cac2019-03-07 22:14:38 +08002230 return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID;
lumarkef1965b2018-09-12 17:42:53 +08002231 }
2232
satoke7c6998e2011-06-03 17:57:59 +09002233 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002234 public void onServiceConnected(ComponentName name, IBinder service) {
2235 synchronized (mMethodMap) {
2236 if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
2237 mCurMethod = IInputMethod.Stub.asInterface(service);
Dianne Hackborncc278702009-09-02 23:07:23 -07002238 if (mCurToken == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002239 Slog.w(TAG, "Service connected without a token!");
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002240 unbindCurrentMethodLocked();
Dianne Hackborncc278702009-09-02 23:07:23 -07002241 return;
2242 }
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002243 if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
lumark90120a82018-08-15 00:33:03 +08002244 // Dispatch display id for InputMethodService to update context display.
2245 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
2246 MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002247 if (mCurClient != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002248 clearClientSessionLocked(mCurClient);
2249 requestClientSessionLocked(mCurClient);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002250 }
2251 }
2252 }
2253 }
2254
Jeff Brownc28867a2013-03-26 15:42:39 -07002255 void onSessionCreated(IInputMethod method, IInputMethodSession session,
2256 InputChannel channel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002257 synchronized (mMethodMap) {
2258 if (mCurMethod != null && method != null
2259 && mCurMethod.asBinder() == method.asBinder()) {
2260 if (mCurClient != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002261 clearClientSessionLocked(mCurClient);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002262 mCurClient.curSession = new SessionState(mCurClient,
Jeff Brownc28867a2013-03-26 15:42:39 -07002263 method, session, channel);
Yohei Yukawa87ca8402017-02-07 00:13:14 -08002264 InputBindResult res = attachNewInputLocked(
Yohei Yukawa42194222018-10-21 20:14:40 -07002265 StartInputReason.SESSION_CREATED_BY_IME, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002266 if (res.method != null) {
2267 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
Yohei Yukawa33e81792015-11-17 21:14:42 -08002268 MSG_BIND_CLIENT, mCurClient.client, res));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002269 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002270 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002271 }
2272 }
2273 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002274
2275 // Session abandoned. Close its associated input channel.
2276 channel.dispose();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002277 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002278
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002279 void unbindCurrentMethodLocked() {
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002280 if (mVisibleBound) {
2281 mContext.unbindService(mVisibleConnection);
2282 mVisibleBound = false;
2283 }
2284
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002285 if (mHaveConnection) {
2286 mContext.unbindService(this);
2287 mHaveConnection = false;
2288 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002289
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002290 if (mCurToken != null) {
2291 try {
lumark90120a82018-08-15 00:33:03 +08002292 if (DEBUG) {
2293 Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
2294 + mCurTokenDisplayId);
2295 }
lumark90120a82018-08-15 00:33:03 +08002296 mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002297 } catch (RemoteException e) {
2298 }
lumark7570cac2019-03-07 22:14:38 +08002299 // Set IME window status as invisible when unbind current method.
2300 mImeWindowVis = 0;
2301 mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
2302 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002303 mCurToken = null;
lumark90120a82018-08-15 00:33:03 +08002304 mCurTokenDisplayId = INVALID_DISPLAY;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002305 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002306
The Android Open Source Project10592532009-03-18 17:39:46 -07002307 mCurId = null;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002308 clearCurMethodLocked();
Yohei Yukawabc7b5262015-11-17 17:38:41 -08002309 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002310
Yohei Yukawa4afd9332018-10-21 10:43:53 -07002311 void resetCurrentMethodAndClient(@UnbindReason int unbindClientReason) {
Yohei Yukawabc7b5262015-11-17 17:38:41 -08002312 mCurMethodId = null;
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002313 unbindCurrentMethodLocked();
Yohei Yukawa33e81792015-11-17 21:14:42 -08002314 unbindCurrentClientLocked(unbindClientReason);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002315 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002316
2317 void requestClientSessionLocked(ClientState cs) {
2318 if (!cs.sessionRequested) {
2319 if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
2320 InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString());
2321 cs.sessionRequested = true;
2322 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOOO(
2323 MSG_CREATE_SESSION, mCurMethod, channels[1],
2324 new MethodCallback(this, mCurMethod, channels[0])));
2325 }
2326 }
2327
2328 void clearClientSessionLocked(ClientState cs) {
2329 finishSessionLocked(cs.curSession);
2330 cs.curSession = null;
2331 cs.sessionRequested = false;
2332 }
2333
2334 private void finishSessionLocked(SessionState sessionState) {
2335 if (sessionState != null) {
2336 if (sessionState.session != null) {
2337 try {
2338 sessionState.session.finishSession();
2339 } catch (RemoteException e) {
2340 Slog.w(TAG, "Session failed to close due to remote exception", e);
Yohei Yukawa849443c2019-01-21 09:02:25 -08002341 updateSystemUiLocked(0 /* vis */, mBackDisposition);
Jeff Brownc28867a2013-03-26 15:42:39 -07002342 }
2343 sessionState.session = null;
2344 }
2345 if (sessionState.channel != null) {
2346 sessionState.channel.dispose();
2347 sessionState.channel = null;
Devin Taylor0c33ed22010-02-23 13:26:46 -06002348 }
2349 }
2350 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002351
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002352 void clearCurMethodLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002353 if (mCurMethod != null) {
Yohei Yukawaac9311e2018-11-20 19:25:23 -08002354 final int numClients = mClients.size();
2355 for (int i = 0; i < numClients; ++i) {
2356 clearClientSessionLocked(mClients.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002357 }
Devin Taylor0c33ed22010-02-23 13:26:46 -06002358
Jeff Brownc28867a2013-03-26 15:42:39 -07002359 finishSessionLocked(mEnabledSession);
Devin Taylor0c33ed22010-02-23 13:26:46 -06002360 mEnabledSession = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002361 mCurMethod = null;
2362 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002363 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002364 mStatusBar.setIconVisibility(mSlotIme, false);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002365 }
Yohei Yukawa2bc66172017-02-08 11:13:25 -08002366 mInFullscreenMode = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002367 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002368
satoke7c6998e2011-06-03 17:57:59 +09002369 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002370 public void onServiceDisconnected(ComponentName name) {
Yohei Yukawa817d5f72017-01-04 20:15:02 -08002371 // Note that mContext.unbindService(this) does not trigger this. Hence if we are here the
2372 // disconnection is not intended by IMMS (e.g. triggered because the current IMS crashed),
2373 // which is irregular but can eventually happen for everyone just by continuing using the
2374 // device. Thus it is important to make sure that all the internal states are properly
2375 // refreshed when this method is called back. Running
2376 // adb install -r <APK that implements the current IME>
2377 // would be a good way to trigger such a situation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002378 synchronized (mMethodMap) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002379 if (DEBUG) Slog.v(TAG, "Service disconnected: " + name
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002380 + " mCurIntent=" + mCurIntent);
2381 if (mCurMethod != null && mCurIntent != null
2382 && name.equals(mCurIntent.getComponent())) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002383 clearCurMethodLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002384 // We consider this to be a new bind attempt, since the system
2385 // should now try to restart the service for us.
2386 mLastBindTime = SystemClock.uptimeMillis();
2387 mShowRequested = mInputShown;
2388 mInputShown = false;
Yohei Yukawab7526452018-10-21 20:15:17 -07002389 unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002390 }
2391 }
2392 }
2393
Yohei Yukawaeec552e2018-09-09 20:48:41 -07002394 @BinderThread
Yohei Yukawa41b094f2018-09-09 23:58:45 -07002395 private void updateStatusIcon(@NonNull IBinder token, String packageName,
2396 @DrawableRes int iconId) {
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002397 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002398 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002399 return;
2400 }
2401 final long ident = Binder.clearCallingIdentity();
2402 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002403 if (iconId == 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002404 if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
Dianne Hackborn661cd522011-08-22 00:26:20 -07002405 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002406 mStatusBar.setIconVisibility(mSlotIme, false);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002407 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002408 } else if (packageName != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002409 if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002410 CharSequence contentDescription = null;
2411 try {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002412 // Use PackageManager to load label
2413 final PackageManager packageManager = mContext.getPackageManager();
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002414 contentDescription = packageManager.getApplicationLabel(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002415 mIPackageManager.getApplicationInfo(packageName, 0,
2416 mSettings.getCurrentUserId()));
2417 } catch (RemoteException e) {
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002418 /* ignore */
2419 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002420 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002421 mStatusBar.setIcon(mSlotIme, packageName, iconId, 0,
Dianne Hackborn661cd522011-08-22 00:26:20 -07002422 contentDescription != null
2423 ? contentDescription.toString() : null);
Jason Monk3e189872016-01-12 09:10:34 -05002424 mStatusBar.setIconVisibility(mSlotIme, true);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002425 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002426 }
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002427 } finally {
2428 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002429 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002430 }
2431 }
2432
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002433 private boolean shouldShowImeSwitcherLocked(int visibility) {
satok7cfc0ed2011-06-20 21:29:36 +09002434 if (!mShowOngoingImeSwitcherForPhones) return false;
Jason Monk807ef762014-05-08 15:47:46 -04002435 if (mSwitchingDialog != null) return false;
Yohei Yukawad2bc3092017-07-31 15:37:14 -07002436 if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
2437 && mKeyguardManager != null && mKeyguardManager.isKeyguardSecure()) return false;
Tarandeep Singheadb1392018-11-09 18:15:57 +01002438 if ((visibility & InputMethodService.IME_ACTIVE) == 0
2439 || (visibility & InputMethodService.IME_INVISIBLE) != 0) {
2440 return false;
2441 }
Seigo Nonaka7309b122015-08-17 18:34:13 -07002442 if (mWindowManagerInternal.isHardKeyboardAvailable()) {
Yohei Yukawaaf023f22019-06-21 16:38:22 -07002443 // When physical keyboard is attached, we show the ime switcher (or notification if
2444 // NavBar is not available) because SHOW_IME_WITH_HARD_KEYBOARD settings currently
2445 // exists in the IME switcher dialog. Might be OK to remove this condition once
2446 // SHOW_IME_WITH_HARD_KEYBOARD settings finds a good place to live.
2447 return true;
Yohei Yukawa89398382016-03-29 11:37:04 -07002448 } else if ((visibility & InputMethodService.IME_VISIBLE) == 0) {
2449 return false;
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002450 }
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002451
2452 List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
2453 final int N = imis.size();
2454 if (N > 2) return true;
2455 if (N < 1) return false;
2456 int nonAuxCount = 0;
2457 int auxCount = 0;
2458 InputMethodSubtype nonAuxSubtype = null;
2459 InputMethodSubtype auxSubtype = null;
2460 for(int i = 0; i < N; ++i) {
2461 final InputMethodInfo imi = imis.get(i);
2462 final List<InputMethodSubtype> subtypes =
2463 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
2464 final int subtypeCount = subtypes.size();
2465 if (subtypeCount == 0) {
2466 ++nonAuxCount;
2467 } else {
2468 for (int j = 0; j < subtypeCount; ++j) {
2469 final InputMethodSubtype subtype = subtypes.get(j);
2470 if (!subtype.isAuxiliary()) {
2471 ++nonAuxCount;
2472 nonAuxSubtype = subtype;
2473 } else {
2474 ++auxCount;
2475 auxSubtype = subtype;
satok7cfc0ed2011-06-20 21:29:36 +09002476 }
2477 }
satok7cfc0ed2011-06-20 21:29:36 +09002478 }
2479 }
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002480 if (nonAuxCount > 1 || auxCount > 1) {
2481 return true;
2482 } else if (nonAuxCount == 1 && auxCount == 1) {
2483 if (nonAuxSubtype != null && auxSubtype != null
2484 && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
2485 || auxSubtype.overridesImplicitlyEnabledSubtype()
2486 || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
2487 && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
2488 return false;
2489 }
2490 return true;
2491 }
2492 return false;
satok7cfc0ed2011-06-20 21:29:36 +09002493 }
2494
John Spurlocke0980502013-10-25 11:59:29 -04002495 private boolean isKeyguardLocked() {
2496 return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
2497 }
2498
Yohei Yukawad6475a62017-04-17 10:35:27 -07002499 @BinderThread
satokdbf29502011-08-25 15:28:23 +09002500 @SuppressWarnings("deprecation")
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08002501 private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
lumark7570cac2019-03-07 22:14:38 +08002502 final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();
2503
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002504 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002505 if (!calledWithValidTokenLocked(token)) {
2506 return;
2507 }
lumark7570cac2019-03-07 22:14:38 +08002508 // Skip update IME status when current token display is not same as focused display.
2509 // Note that we still need to update IME status when focusing external display
2510 // that does not support system decoration and fallback to show IME on default
2511 // display since it is intentional behavior.
2512 if (mCurTokenDisplayId != topFocusedDisplayId
2513 && mCurTokenDisplayId != FALLBACK_DISPLAY_ID) {
2514 return;
2515 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002516 mImeWindowVis = vis;
2517 mBackDisposition = backDisposition;
Yohei Yukawa849443c2019-01-21 09:02:25 -08002518 updateSystemUiLocked(vis, backDisposition);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002519 }
Yohei Yukawad6475a62017-04-17 10:35:27 -07002520
2521 final boolean dismissImeOnBackKeyPressed;
2522 switch (backDisposition) {
2523 case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
2524 dismissImeOnBackKeyPressed = true;
2525 break;
2526 case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
2527 dismissImeOnBackKeyPressed = false;
2528 break;
2529 default:
2530 case InputMethodService.BACK_DISPOSITION_DEFAULT:
2531 dismissImeOnBackKeyPressed = ((vis & InputMethodService.IME_VISIBLE) != 0);
2532 break;
2533 }
Yohei Yukawaee2a7ed2017-02-15 21:38:57 -08002534 mWindowManagerInternal.updateInputMethodWindowStatus(token,
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002535 (vis & InputMethodService.IME_VISIBLE) != 0, dismissImeOnBackKeyPressed);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002536 }
2537
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002538 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08002539 private void reportStartInput(@NonNull IBinder token, IBinder startInputToken) {
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002540 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002541 if (!calledWithValidTokenLocked(token)) {
2542 return;
2543 }
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002544 final IBinder targetWindow = mImeTargetWindowMap.get(startInputToken);
2545 if (targetWindow != null && mLastImeTargetWindow != targetWindow) {
2546 mWindowManagerInternal.updateInputMethodTargetWindow(token, targetWindow);
2547 }
2548 mLastImeTargetWindow = targetWindow;
2549 }
2550 }
2551
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002552 // Caution! This method is called in this class. Handle multi-user carefully
Yohei Yukawa849443c2019-01-21 09:02:25 -08002553 private void updateSystemUiLocked(int vis, int backDisposition) {
2554 if (mCurToken == null) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002555 return;
2556 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01002557 if (DEBUG) {
2558 Slog.d(TAG, "IME window vis: " + vis
2559 + " active: " + (vis & InputMethodService.IME_ACTIVE)
lumark7570cac2019-03-07 22:14:38 +08002560 + " inv: " + (vis & InputMethodService.IME_INVISIBLE)
2561 + " displayId: " + mCurTokenDisplayId);
Tarandeep Singheadb1392018-11-09 18:15:57 +01002562 }
2563
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002564 // TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
2565 // all updateSystemUi happens on system previlege.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002566 final long ident = Binder.clearCallingIdentity();
satok06487a52010-10-29 11:37:18 +09002567 try {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002568 // apply policy for binder calls
2569 if (vis != 0 && isKeyguardLocked() && !mCurClientInKeyguard) {
2570 vis = 0;
satok06487a52010-10-29 11:37:18 +09002571 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002572 // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
2573 final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
2574 if (mStatusBar != null) {
lumark7570cac2019-03-07 22:14:38 +08002575 mStatusBar.setImeWindowStatus(mCurTokenDisplayId, mCurToken, vis, backDisposition,
Tarandeep Singh07b318b2019-07-17 11:12:04 -07002576 needsToShowImeSwitcher, false /*isMultiClientImeEnabled*/);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002577 }
2578 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
2579 if (imi != null && needsToShowImeSwitcher) {
2580 // Used to load label
2581 final CharSequence title = mRes.getText(
2582 com.android.internal.R.string.select_input_method);
2583 final CharSequence summary = InputMethodUtils.getImeAndSubtypeDisplayName(
2584 mContext, imi, mCurrentSubtype);
Chris Wren1ce4b6d2015-06-11 10:19:43 -04002585 mImeSwitcherNotification.setContentTitle(title)
2586 .setContentText(summary)
2587 .setContentIntent(mImeSwitchPendingIntent);
Seigo Nonaka7309b122015-08-17 18:34:13 -07002588 try {
Charles Chenea6e7f02018-11-19 21:37:45 +08002589 // TODO(b/120076400): Figure out what is the best behavior
Seigo Nonaka7309b122015-08-17 18:34:13 -07002590 if ((mNotificationManager != null)
Charles Chenea6e7f02018-11-19 21:37:45 +08002591 && !mIWindowManager.hasNavigationBar(DEFAULT_DISPLAY)) {
Seigo Nonaka7309b122015-08-17 18:34:13 -07002592 if (DEBUG) {
2593 Slog.d(TAG, "--- show notification: label = " + summary);
2594 }
2595 mNotificationManager.notifyAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04002596 SystemMessage.NOTE_SELECT_INPUT_METHOD,
Seigo Nonaka7309b122015-08-17 18:34:13 -07002597 mImeSwitcherNotification.build(), UserHandle.ALL);
2598 mNotificationShown = true;
Dianne Hackborn661cd522011-08-22 00:26:20 -07002599 }
Seigo Nonaka7309b122015-08-17 18:34:13 -07002600 } catch (RemoteException e) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002601 }
2602 } else {
2603 if (mNotificationShown && mNotificationManager != null) {
2604 if (DEBUG) {
2605 Slog.d(TAG, "--- hide notification");
satok7cfc0ed2011-06-20 21:29:36 +09002606 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002607 mNotificationManager.cancelAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04002608 SystemMessage.NOTE_SELECT_INPUT_METHOD, UserHandle.ALL);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002609 mNotificationShown = false;
satok7cfc0ed2011-06-20 21:29:36 +09002610 }
satok06487a52010-10-29 11:37:18 +09002611 }
2612 } finally {
2613 Binder.restoreCallingIdentity(ident);
2614 }
2615 }
2616
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002617 void updateFromSettingsLocked(boolean enabledMayChange) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07002618 updateInputMethodsFromSettingsLocked(enabledMayChange);
2619 updateKeyboardFromSettingsLocked();
2620 }
2621
2622 void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002623 if (enabledMayChange) {
2624 List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
2625 for (int i=0; i<enabled.size(); i++) {
2626 // We allow the user to select "disabled until used" apps, so if they
2627 // are enabling one of those here we now need to make it enabled.
2628 InputMethodInfo imm = enabled.get(i);
2629 try {
2630 ApplicationInfo ai = mIPackageManager.getApplicationInfo(imm.getPackageName(),
2631 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
2632 mSettings.getCurrentUserId());
Satoshi Kataoka7987a312013-04-17 18:59:33 +09002633 if (ai != null && ai.enabledSetting
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002634 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09002635 if (DEBUG) {
2636 Slog.d(TAG, "Update state(" + imm.getId()
2637 + "): DISABLED_UNTIL_USED -> DEFAULT");
2638 }
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002639 mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
2640 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
Dianne Hackborn3fa3c28a2013-03-26 16:15:41 -07002641 PackageManager.DONT_KILL_APP, mSettings.getCurrentUserId(),
2642 mContext.getBasePackageName());
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002643 }
2644 } catch (RemoteException e) {
2645 }
2646 }
2647 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002648 // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and
2649 // ENABLED_INPUT_METHODS is taking care of keeping them correctly in
2650 // sync, so we will never have a DEFAULT_INPUT_METHOD that is not
2651 // enabled.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002652 String id = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09002653 // There is no input method selected, try to choose new applicable input method.
2654 if (TextUtils.isEmpty(id) && chooseNewDefaultIMELocked()) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002655 id = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09002656 }
2657 if (!TextUtils.isEmpty(id)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002658 try {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09002659 setInputMethodLocked(id, mSettings.getSelectedInputMethodSubtypeId(id));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002660 } catch (IllegalArgumentException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002661 Slog.w(TAG, "Unknown input method from prefs: " + id, e);
Yohei Yukawab7526452018-10-21 20:15:17 -07002662 resetCurrentMethodAndClient(UnbindReason.SWITCH_IME_FAILED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002663 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002664 } else {
2665 // There is no longer an input method set, so stop any current one.
Yohei Yukawab7526452018-10-21 20:15:17 -07002666 resetCurrentMethodAndClient(UnbindReason.NO_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002667 }
Yohei Yukawa3d46bab2014-05-30 18:10:18 +09002668 // Here is not the perfect place to reset the switching controller. Ideally
2669 // mSwitchingController and mSettings should be able to share the same state.
2670 // TODO: Make sure that mSwitchingController and mSettings are sharing the
2671 // the same enabled IMEs list.
2672 mSwitchingController.resetCircularListLocked(mContext);
Michael Wright7b5a96b2014-08-09 19:28:42 -07002673
2674 }
2675
2676 public void updateKeyboardFromSettingsLocked() {
2677 mShowImeWithHardKeyboard = mSettings.isShowImeWithHardKeyboardEnabled();
2678 if (mSwitchingDialog != null
2679 && mSwitchingDialogTitleView != null
2680 && mSwitchingDialog.isShowing()) {
2681 final Switch hardKeySwitch = (Switch)mSwitchingDialogTitleView.findViewById(
2682 com.android.internal.R.id.hard_keyboard_switch);
2683 hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
2684 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002686
satokab751aa2010-09-14 19:17:36 +09002687 /* package */ void setInputMethodLocked(String id, int subtypeId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002688 InputMethodInfo info = mMethodMap.get(id);
2689 if (info == null) {
satok913a8922010-08-26 21:53:41 +09002690 throw new IllegalArgumentException("Unknown id: " + id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002691 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002692
satokd81e9502012-05-21 12:58:45 +09002693 // See if we need to notify a subtype change within the same IME.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002694 if (id.equals(mCurMethodId)) {
satokd81e9502012-05-21 12:58:45 +09002695 final int subtypeCount = info.getSubtypeCount();
2696 if (subtypeCount <= 0) {
2697 return;
satokcd7cd292010-11-20 15:46:23 +09002698 }
satokd81e9502012-05-21 12:58:45 +09002699 final InputMethodSubtype oldSubtype = mCurrentSubtype;
2700 final InputMethodSubtype newSubtype;
2701 if (subtypeId >= 0 && subtypeId < subtypeCount) {
2702 newSubtype = info.getSubtypeAt(subtypeId);
2703 } else {
2704 // If subtype is null, try to find the most applicable one from
2705 // getCurrentInputMethodSubtype.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002706 newSubtype = getCurrentInputMethodSubtypeLocked();
satokd81e9502012-05-21 12:58:45 +09002707 }
2708 if (newSubtype == null || oldSubtype == null) {
2709 Slog.w(TAG, "Illegal subtype state: old subtype = " + oldSubtype
2710 + ", new subtype = " + newSubtype);
2711 return;
2712 }
2713 if (newSubtype != oldSubtype) {
2714 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
2715 if (mCurMethod != null) {
2716 try {
Yohei Yukawa849443c2019-01-21 09:02:25 -08002717 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
satokd81e9502012-05-21 12:58:45 +09002718 mCurMethod.changeInputMethodSubtype(newSubtype);
2719 } catch (RemoteException e) {
2720 Slog.w(TAG, "Failed to call changeInputMethodSubtype");
satokab751aa2010-09-14 19:17:36 +09002721 }
2722 }
2723 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002724 return;
2725 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002726
satokd81e9502012-05-21 12:58:45 +09002727 // Changing to a different IME.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002728 final long ident = Binder.clearCallingIdentity();
2729 try {
satokab751aa2010-09-14 19:17:36 +09002730 // Set a subtype to this input method.
2731 // subtypeId the name of a subtype which will be set.
satok723a27e2010-11-11 14:58:11 +09002732 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, false);
2733 // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
2734 // because mCurMethodId is stored as a history in
2735 // setSelectedInputMethodAndSubtypeLocked().
2736 mCurMethodId = id;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002737
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07002738 if (LocalServices.getService(ActivityManagerInternal.class).isSystemReady()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002739 Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08002740 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002741 intent.putExtra("input_method_id", id);
Amith Yamasanicd757062012-10-19 18:23:52 -07002742 mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002743 }
Yohei Yukawab7526452018-10-21 20:15:17 -07002744 unbindCurrentClientLocked(UnbindReason.SWITCH_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002745 } finally {
2746 Binder.restoreCallingIdentity(ident);
2747 }
2748 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002749
satok42c5a162011-05-26 16:46:14 +09002750 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -08002751 public boolean showSoftInput(IInputMethodClient client, int flags,
2752 ResultReceiver resultReceiver) {
Dianne Hackborncef65ee2010-09-30 18:27:22 -07002753 int uid = Binder.getCallingUid();
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002754 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08002755 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002756 return false;
2757 }
2758 final long ident = Binder.clearCallingIdentity();
2759 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002760 if (mCurClient == null || client == null
2761 || mCurClient.client.asBinder() != client.asBinder()) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002762 // We need to check if this is the current client with
2763 // focus in the window manager, to allow this call to
2764 // be made before input is started in it.
Yohei Yukawa41f89c32018-09-19 14:30:04 -07002765 final ClientState cs = mClients.get(client.asBinder());
2766 if (cs == null) {
2767 throw new IllegalArgumentException("unknown client " + client.asBinder());
2768 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002769 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
2770 cs.selfReportedDisplayId)) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002771 Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002772 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002773 }
2774 }
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002775 if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
The Android Open Source Project4df24232009-03-05 14:34:35 -08002776 return showCurrentInputLocked(flags, resultReceiver);
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002777 } finally {
2778 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002779 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002780 }
2781 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002782
Andreas Gamped6d42062018-07-20 13:08:21 -07002783 @GuardedBy("mMethodMap")
The Android Open Source Project4df24232009-03-05 14:34:35 -08002784 boolean showCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002785 mShowRequested = true;
Anna Galusza9b278112016-01-04 11:37:37 -08002786 if (mAccessibilityRequestingNoSoftKeyboard) {
2787 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002788 }
Anna Galusza9b278112016-01-04 11:37:37 -08002789
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002790 if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
2791 mShowExplicitlyRequested = true;
2792 mShowForced = true;
Anna Galusza9b278112016-01-04 11:37:37 -08002793 } else if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
2794 mShowExplicitlyRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002795 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002796
Dianne Hackborncc278702009-09-02 23:07:23 -07002797 if (!mSystemReady) {
2798 return false;
2799 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002800
The Android Open Source Project4df24232009-03-05 14:34:35 -08002801 boolean res = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002802 if (mCurMethod != null) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002803 if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + mCurToken);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002804 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
2805 MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod,
2806 resultReceiver));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002807 mInputShown = true;
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002808 if (mHaveConnection && !mVisibleBound) {
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002809 bindCurrentInputMethodServiceLocked(
Yohei Yukawaa67a4592017-03-30 15:57:02 -07002810 mCurIntent, mVisibleConnection, IME_VISIBLE_BIND_FLAGS);
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002811 mVisibleBound = true;
2812 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08002813 res = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002814 } else if (mHaveConnection && SystemClock.uptimeMillis()
satok59b424c2011-09-30 17:21:46 +09002815 >= (mLastBindTime+TIME_TO_RECONNECT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002816 // The client has asked to have the input method shown, but
2817 // we have been sitting here too long with a connection to the
2818 // service and no interface received, so let's disconnect/connect
2819 // to try to prod things along.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002820 EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002821 SystemClock.uptimeMillis()-mLastBindTime,1);
satok59b424c2011-09-30 17:21:46 +09002822 Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002823 mContext.unbindService(this);
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002824 bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002825 } else {
2826 if (DEBUG) {
2827 Slog.d(TAG, "Can't show input: connection = " + mHaveConnection + ", time = "
2828 + ((mLastBindTime+TIME_TO_RECONNECT) - SystemClock.uptimeMillis()));
2829 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002830 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002831
The Android Open Source Project4df24232009-03-05 14:34:35 -08002832 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002833 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002834
satok42c5a162011-05-26 16:46:14 +09002835 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -08002836 public boolean hideSoftInput(IInputMethodClient client, int flags,
2837 ResultReceiver resultReceiver) {
Dianne Hackborncef65ee2010-09-30 18:27:22 -07002838 int uid = Binder.getCallingUid();
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002839 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08002840 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002841 return false;
2842 }
2843 final long ident = Binder.clearCallingIdentity();
2844 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002845 if (mCurClient == null || client == null
2846 || mCurClient.client.asBinder() != client.asBinder()) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002847 // We need to check if this is the current client with
2848 // focus in the window manager, to allow this call to
2849 // be made before input is started in it.
Yohei Yukawa41f89c32018-09-19 14:30:04 -07002850 final ClientState cs = mClients.get(client.asBinder());
2851 if (cs == null) {
2852 throw new IllegalArgumentException("unknown client " + client.asBinder());
2853 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002854 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
2855 cs.selfReportedDisplayId)) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002856 if (DEBUG) {
2857 Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002858 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08002859 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002860 }
2861 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002862
Joe Onorato8a9b2202010-02-26 18:56:32 -08002863 if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
The Android Open Source Project4df24232009-03-05 14:34:35 -08002864 return hideCurrentInputLocked(flags, resultReceiver);
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002865 } finally {
2866 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002867 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002868 }
2869 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002870
The Android Open Source Project4df24232009-03-05 14:34:35 -08002871 boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002872 if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
2873 && (mShowExplicitlyRequested || mShowForced)) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002874 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 -08002875 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002876 }
2877 if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002878 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 -08002879 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002880 }
Seigo Nonakaec928652015-06-10 15:31:20 +09002881
2882 // There is a chance that IMM#hideSoftInput() is called in a transient state where
2883 // IMMS#InputShown is already updated to be true whereas IMMS#mImeWindowVis is still waiting
2884 // to be updated with the new value sent from IME process. Even in such a transient state
2885 // historically we have accepted an incoming call of IMM#hideSoftInput() from the
2886 // application process as a valid request, and have even promised such a behavior with CTS
2887 // since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only
2888 // IMMS#InputShown indicates that the software keyboard is shown.
2889 // TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
2890 final boolean shouldHideSoftInput = (mCurMethod != null) && (mInputShown ||
2891 (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002892 boolean res;
Seigo Nonakaec928652015-06-10 15:31:20 +09002893 if (shouldHideSoftInput) {
2894 // The IME will report its visible state again after the following message finally
2895 // delivered to the IME process as an IPC. Hence the inconsistency between
2896 // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
2897 // the final state.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002898 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
2899 MSG_HIDE_SOFT_INPUT, mCurMethod, resultReceiver));
2900 res = true;
2901 } else {
2902 res = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002903 }
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002904 if (mHaveConnection && mVisibleBound) {
2905 mContext.unbindService(mVisibleConnection);
2906 mVisibleBound = false;
2907 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002908 mInputShown = false;
2909 mShowRequested = false;
2910 mShowExplicitlyRequested = false;
2911 mShowForced = false;
The Android Open Source Project4df24232009-03-05 14:34:35 -08002912 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002913 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002914
Yohei Yukawa2553e482017-12-15 15:47:33 -08002915 @NonNull
satok42c5a162011-05-26 16:46:14 +09002916 @Override
Yohei Yukawa05c25f82016-02-22 12:41:17 -08002917 public InputBindResult startInputOrWindowGainedFocus(
Yohei Yukawadc66e522018-10-21 10:43:14 -07002918 @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002919 @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
2920 int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
Yohei Yukawadc66e522018-10-21 10:43:14 -07002921 @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) {
Yohei Yukawa80498d52018-06-21 16:24:36 -07002922 if (windowToken == null) {
2923 Slog.e(TAG, "windowToken cannot be null.");
2924 return InputBindResult.NULL;
Yohei Yukawa05c25f82016-02-22 12:41:17 -08002925 }
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002926 final int callingUserId = UserHandle.getCallingUserId();
2927 final int userId;
Yohei Yukawa716897c2019-01-22 00:00:53 -08002928 if (attribute != null && attribute.targetInputMethodUser != null
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002929 && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
2930 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Yohei Yukawa670abea2019-01-28 00:00:50 -08002931 "Using EditorInfo.targetInputMethodUser requires INTERACT_ACROSS_USERS_FULL.");
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002932 userId = attribute.targetInputMethodUser.getIdentifier();
2933 if (!mUserManagerInternal.isUserRunning(userId)) {
2934 // There is a chance that we hit here because of race condition. Let's just return
2935 // an error code instead of crashing the caller process, which at least has
2936 // INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important process.
2937 Slog.e(TAG, "User #" + userId + " is not running.");
2938 return InputBindResult.INVALID_USER;
2939 }
2940 } else {
2941 userId = callingUserId;
2942 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002943 final InputBindResult result;
2944 synchronized (mMethodMap) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002945 final long ident = Binder.clearCallingIdentity();
2946 try {
2947 result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client,
2948 windowToken, startInputFlags, softInputMode, windowFlags, attribute,
2949 inputContext, missingMethods, unverifiedTargetSdkVersion, userId);
2950 } finally {
2951 Binder.restoreCallingIdentity(ident);
2952 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002953 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002954 if (result == null) {
2955 // This must never happen, but just in case.
2956 Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
Yohei Yukawaa468d702018-10-21 11:42:34 -07002957 + InputMethodDebug.startInputReasonToString(startInputReason)
Yohei Yukawa2553e482017-12-15 15:47:33 -08002958 + " windowFlags=#" + Integer.toHexString(windowFlags)
2959 + " editorInfo=" + attribute);
2960 return InputBindResult.NULL;
2961 }
2962 return result;
Yohei Yukawa05c25f82016-02-22 12:41:17 -08002963 }
2964
Yohei Yukawa2553e482017-12-15 15:47:33 -08002965 @NonNull
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002966 private InputBindResult startInputOrWindowGainedFocusInternalLocked(
Yohei Yukawadc66e522018-10-21 10:43:14 -07002967 @StartInputReason int startInputReason, IInputMethodClient client,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002968 @NonNull IBinder windowToken, @StartInputFlags int startInputFlags,
2969 @SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute,
2970 IInputContext inputContext, @MissingMethodFlags int missingMethods,
Yohei Yukawa4391c202019-01-28 00:49:10 -08002971 int unverifiedTargetSdkVersion, @UserIdInt int userId) {
Yohei Yukawa67464522019-01-28 00:50:09 -08002972 if (DEBUG) {
2973 Slog.v(TAG, "startInputOrWindowGainedFocusInternalLocked: reason="
2974 + InputMethodDebug.startInputReasonToString(startInputReason)
2975 + " client=" + client.asBinder()
2976 + " inputContext=" + inputContext
2977 + " missingMethods="
2978 + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
2979 + " attribute=" + attribute
2980 + " startInputFlags="
2981 + InputMethodDebug.startInputFlagsToString(startInputFlags)
2982 + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode)
2983 + " windowFlags=#" + Integer.toHexString(windowFlags)
2984 + " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion);
2985 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002986
Yohei Yukawa67464522019-01-28 00:50:09 -08002987 final int windowDisplayId = mWindowManagerInternal.getDisplayIdForWindow(windowToken);
2988
2989 final ClientState cs = mClients.get(client.asBinder());
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002990 if (cs == null) {
Yohei Yukawa67464522019-01-28 00:50:09 -08002991 throw new IllegalArgumentException("unknown client " + client.asBinder());
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002992 }
2993 if (cs.selfReportedDisplayId != windowDisplayId) {
2994 Slog.e(TAG, "startInputOrWindowGainedFocusInternal: display ID mismatch."
2995 + " from client:" + cs.selfReportedDisplayId
2996 + " from window:" + windowDisplayId);
2997 return InputBindResult.DISPLAY_ID_MISMATCH;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002998 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08002999
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003000 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
3001 cs.selfReportedDisplayId)) {
3002 // Check with the window manager to make sure this client actually
3003 // has a window with focus. If not, reject. This is thread safe
3004 // because if the focus changes some time before or after, the
3005 // next client receiving focus that has any interest in input will
3006 // be calling through here after that change happens.
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003007 if (DEBUG) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003008 Slog.w(TAG, "Focus gain on non-focused client " + cs.client
3009 + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003010 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003011 return InputBindResult.NOT_IME_TARGET_WINDOW;
3012 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003013
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003014 // cross-profile access is always allowed here to allow profile-switching.
3015 if (!mSettings.isCurrentProfile(userId)) {
3016 Slog.w(TAG, "A background user is requesting window. Hiding IME.");
3017 Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
3018 + " a background user, use EditorInfo.targetInputMethodUser with"
3019 + " INTERACT_ACROSS_USERS_FULL permission.");
3020 hideCurrentInputLocked(0, null);
3021 return InputBindResult.INVALID_USER;
3022 }
3023
Tarandeep Singhcf5ff822019-07-08 14:06:27 -07003024 if (userId != mSettings.getCurrentUserId()) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003025 switchUserLocked(userId);
3026 }
3027 // Master feature flag that overrides other conditions and forces IME preRendering.
3028 if (DEBUG) {
3029 Slog.v(TAG, "IME PreRendering MASTER flag: "
Yohei Yukawa67464522019-01-28 00:50:09 -08003030 + DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() + ", LowRam: " + mIsLowRam);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003031 }
3032 // pre-rendering not supported on low-ram devices.
3033 cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam;
3034
3035 if (mCurFocusedWindow == windowToken) {
3036 if (DEBUG) {
3037 Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
3038 + " attribute=" + attribute + ", token = " + windowToken);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003039 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003040 if (attribute != null) {
3041 return startInputUncheckedLocked(cs, inputContext, missingMethods,
3042 attribute, startInputFlags, startInputReason);
3043 }
3044 return new InputBindResult(
3045 InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07003046 null, null, null, -1, null);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003047 }
3048 mCurFocusedWindow = windowToken;
3049 mCurFocusedWindowSoftInputMode = softInputMode;
3050 mCurFocusedWindowClient = cs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003051
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003052 // Should we auto-show the IME even if the caller has not
3053 // specified what should be done with it?
3054 // We only do this automatically if the window can resize
3055 // to accommodate the IME (so what the user sees will give
3056 // them good context without input information being obscured
3057 // by the IME) or if running on a large screen where there
3058 // is more room for the target window + IME.
3059 final boolean doAutoShow =
Yohei Yukawa6e875592019-01-28 00:49:30 -08003060 (softInputMode & LayoutParams.SOFT_INPUT_MASK_ADJUST)
3061 == LayoutParams.SOFT_INPUT_ADJUST_RESIZE
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003062 || mRes.getConfiguration().isLayoutSizeAtLeast(
3063 Configuration.SCREENLAYOUT_SIZE_LARGE);
Yohei Yukawa67464522019-01-28 00:50:09 -08003064 final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003065
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003066 // We want to start input before showing the IME, but after closing
3067 // it. We want to do this after closing it to help the IME disappear
3068 // more quickly (not get stuck behind it initializing itself for the
3069 // new focused input, even if its window wants to hide the IME).
3070 boolean didStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003071
Yohei Yukawa67464522019-01-28 00:50:09 -08003072 InputBindResult res = null;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003073 switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) {
3074 case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003075 if (!isTextEditor || !doAutoShow) {
Yohei Yukawa6e875592019-01-28 00:49:30 -08003076 if (LayoutParams.mayUseInputMethod(windowFlags)) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003077 // There is no focus view, and this window will
3078 // be behind any soft input window, so hide the
3079 // soft input window if it is shown.
3080 if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
3081 hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003082
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003083 // If focused display changed, we should unbind current method
3084 // to make app window in previous display relayout after Ime
3085 // window token removed.
3086 // Note that we can trust client's display ID as long as it matches
3087 // to the display ID obtained from the window.
3088 if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
3089 unbindCurrentMethodLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003090 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003091 }
Yohei Yukawa6e875592019-01-28 00:49:30 -08003092 } else if (isTextEditor && doAutoShow
3093 && (softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003094 // There is a focus view, and we are navigating forward
3095 // into the window, so show the input window for the user.
3096 // We only do this automatically if the window can resize
3097 // to accommodate the IME (so what the user sees will give
3098 // them good context without input information being obscured
3099 // by the IME) or if running on a large screen where there
3100 // is more room for the target window + IME.
3101 if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
3102 if (attribute != null) {
3103 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3104 attribute, startInputFlags, startInputReason);
3105 didStart = true;
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003106 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003107 showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
3108 }
3109 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003110 case LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003111 // Do nothing.
3112 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003113 case LayoutParams.SOFT_INPUT_STATE_HIDDEN:
3114 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003115 if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003116 hideCurrentInputLocked(0, null);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003117 }
3118 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003119 case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003120 if (DEBUG) Slog.v(TAG, "Window asks to hide input");
3121 hideCurrentInputLocked(0, null);
3122 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003123 case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
3124 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003125 if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003126 if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
3127 unverifiedTargetSdkVersion, startInputFlags)) {
3128 if (attribute != null) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003129 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3130 attribute, startInputFlags, startInputReason);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003131 didStart = true;
3132 }
3133 showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
3134 } else {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003135 Slog.e(TAG, "SOFT_INPUT_STATE_VISIBLE is ignored because"
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003136 + " there is no focused view that also returns true from"
3137 + " View#onCheckIsTextEditor()");
3138 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003139 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003140 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003141 case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003142 if (DEBUG) Slog.v(TAG, "Window asks to always show input");
3143 if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
3144 unverifiedTargetSdkVersion, startInputFlags)) {
3145 if (attribute != null) {
3146 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3147 attribute, startInputFlags, startInputReason);
3148 didStart = true;
3149 }
3150 showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
3151 } else {
3152 Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
3153 + " there is no focused view that also returns true from"
3154 + " View#onCheckIsTextEditor()");
3155 }
3156 break;
3157 }
3158
3159 if (!didStart) {
3160 if (attribute != null) {
3161 if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
3162 || (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003163 res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003164 startInputFlags, startInputReason);
3165 } else {
3166 res = InputBindResult.NO_EDITOR;
3167 }
3168 } else {
3169 res = InputBindResult.NULL_EDITOR_INFO;
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003170 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003171 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08003172 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003173 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003174
Guliz Tuncay6908c152017-06-02 16:06:10 -07003175 private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003176 // TODO(yukawa): multi-display support.
Guliz Tuncay6908c152017-06-02 16:06:10 -07003177 final int uid = Binder.getCallingUid();
lumark0b05f9e2018-11-26 15:09:06 +08003178 if (mCurFocusedWindowClient != null && client != null
Tarandeep Singheb570612018-01-29 16:20:32 -08003179 && mCurFocusedWindowClient.client.asBinder() == client.asBinder()) {
Guliz Tuncay6908c152017-06-02 16:06:10 -07003180 return true;
3181 } else if (mCurIntent != null && InputMethodUtils.checkIfPackageBelongsToUid(
3182 mAppOpsManager,
3183 uid,
3184 mCurIntent.getComponent().getPackageName())) {
3185 return true;
Guliz Tuncay6908c152017-06-02 16:06:10 -07003186 }
Guliz Tuncay6908c152017-06-02 16:06:10 -07003187 return false;
3188 }
3189
satok42c5a162011-05-26 16:46:14 +09003190 @Override
Seigo Nonaka14e13912015-05-06 21:04:13 -07003191 public void showInputMethodPickerFromClient(
3192 IInputMethodClient client, int auxiliarySubtypeMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003193 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003194 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003195 return;
3196 }
Guliz Tuncay6908c152017-06-02 16:06:10 -07003197 if(!canShowInputMethodPickerLocked(client)) {
satok47a44912010-10-06 16:03:58 +09003198 Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
Dianne Hackborncef65ee2010-09-30 18:27:22 -07003199 + Binder.getCallingUid() + ": " + client);
Guliz Tuncay6908c152017-06-02 16:06:10 -07003200 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003201 }
3202
satok440aab52010-11-25 09:43:11 +09003203 // Always call subtype picker, because subtype picker is a superset of input method
3204 // picker.
lumark0b05f9e2018-11-26 15:09:06 +08003205 mHandler.sendMessage(mCaller.obtainMessageII(
3206 MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode,
3207 (mCurClient != null) ? mCurClient.selfReportedDisplayId : DEFAULT_DISPLAY));
satokab751aa2010-09-14 19:17:36 +09003208 }
3209 }
3210
lumark0b05f9e2018-11-26 15:09:06 +08003211 @Override
3212 public void showInputMethodPickerFromSystem(IInputMethodClient client, int auxiliarySubtypeMode,
3213 int displayId) {
3214 if (mContext.checkCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
3215 != PackageManager.PERMISSION_GRANTED) {
3216 throw new SecurityException(
3217 "showInputMethodPickerFromSystem requires WRITE_SECURE_SETTINGS permission");
3218 }
3219 // Always call subtype picker, because subtype picker is a superset of input method
3220 // picker.
3221 mHandler.sendMessage(mCaller.obtainMessageII(
3222 MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode, displayId));
3223 }
3224
Tarandeep Singheb570612018-01-29 16:20:32 -08003225 public boolean isInputMethodPickerShownForTest() {
3226 synchronized(mMethodMap) {
3227 if (mSwitchingDialog == null) {
3228 return false;
3229 }
3230 return mSwitchingDialog.isShowing();
3231 }
3232 }
3233
Yohei Yukawa0c1ebff2018-12-27 14:06:28 -08003234 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003235 private void setInputMethod(@NonNull IBinder token, String id) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003236 synchronized (mMethodMap) {
Yohei Yukawa0c1ebff2018-12-27 14:06:28 -08003237 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003238 return;
3239 }
3240 setInputMethodWithSubtypeIdLocked(token, id, NOT_A_SUBTYPE_ID);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003241 }
satok28203512010-11-24 11:06:49 +09003242 }
3243
Yohei Yukawa4773ee12018-12-24 21:13:53 -08003244 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003245 private void setInputMethodAndSubtype(@NonNull IBinder token, String id,
3246 InputMethodSubtype subtype) {
satok28203512010-11-24 11:06:49 +09003247 synchronized (mMethodMap) {
Yohei Yukawa4773ee12018-12-24 21:13:53 -08003248 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003249 return;
3250 }
satok28203512010-11-24 11:06:49 +09003251 if (subtype != null) {
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003252 setInputMethodWithSubtypeIdLocked(token, id,
3253 InputMethodUtils.getSubtypeIdFromHashCode(mMethodMap.get(id),
3254 subtype.hashCode()));
satok28203512010-11-24 11:06:49 +09003255 } else {
3256 setInputMethod(token, id);
3257 }
3258 }
satokab751aa2010-09-14 19:17:36 +09003259 }
3260
satok42c5a162011-05-26 16:46:14 +09003261 @Override
satokb416a712010-11-25 20:42:14 +09003262 public void showInputMethodAndSubtypeEnablerFromClient(
satok217f5482010-12-15 05:19:19 +09003263 IInputMethodClient client, String inputMethodId) {
satokb416a712010-11-25 20:42:14 +09003264 synchronized (mMethodMap) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003265 // TODO(yukawa): Should we verify the display ID?
Yohei Yukawa46d74762019-01-22 10:17:22 -08003266 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003267 return;
3268 }
satok7fee71f2010-12-17 18:54:26 +09003269 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
3270 MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
satokb416a712010-11-25 20:42:14 +09003271 }
3272 }
3273
Yohei Yukawa0c499082018-12-09 18:52:02 -08003274 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003275 private boolean switchToPreviousInputMethod(@NonNull IBinder token) {
satok735cf382010-11-11 20:40:09 +09003276 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003277 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa0c499082018-12-09 18:52:02 -08003278 return false;
3279 }
satokc445bcd2011-01-25 18:57:24 +09003280 final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
satok4fc87d62011-05-20 16:13:43 +09003281 final InputMethodInfo lastImi;
satok208d5632011-05-20 22:13:38 +09003282 if (lastIme != null) {
satok4fc87d62011-05-20 16:13:43 +09003283 lastImi = mMethodMap.get(lastIme.first);
3284 } else {
3285 lastImi = null;
satok735cf382010-11-11 20:40:09 +09003286 }
satok4fc87d62011-05-20 16:13:43 +09003287 String targetLastImiId = null;
3288 int subtypeId = NOT_A_SUBTYPE_ID;
3289 if (lastIme != null && lastImi != null) {
3290 final boolean imiIdIsSame = lastImi.getId().equals(mCurMethodId);
Narayan Kamatha09b4d22016-04-15 18:32:45 +01003291 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
satok4fc87d62011-05-20 16:13:43 +09003292 final int currentSubtypeHash = mCurrentSubtype == null ? NOT_A_SUBTYPE_ID
3293 : mCurrentSubtype.hashCode();
3294 // If the last IME is the same as the current IME and the last subtype is not
3295 // defined, there is no need to switch to the last IME.
3296 if (!imiIdIsSame || lastSubtypeHash != currentSubtypeHash) {
3297 targetLastImiId = lastIme.first;
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003298 subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
satok4fc87d62011-05-20 16:13:43 +09003299 }
3300 }
3301
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003302 if (TextUtils.isEmpty(targetLastImiId)
3303 && !InputMethodUtils.canAddToLastInputMethod(mCurrentSubtype)) {
satok4fc87d62011-05-20 16:13:43 +09003304 // This is a safety net. If the currentSubtype can't be added to the history
3305 // and the framework couldn't find the last ime, we will make the last ime be
3306 // the most applicable enabled keyboard subtype of the system imes.
3307 final List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
3308 if (enabled != null) {
3309 final int N = enabled.size();
3310 final String locale = mCurrentSubtype == null
3311 ? mRes.getConfiguration().locale.toString()
3312 : mCurrentSubtype.getLocale();
3313 for (int i = 0; i < N; ++i) {
3314 final InputMethodInfo imi = enabled.get(i);
Yohei Yukawafd70fe82018-04-08 12:19:56 -07003315 if (imi.getSubtypeCount() > 0 && imi.isSystem()) {
satok4fc87d62011-05-20 16:13:43 +09003316 InputMethodSubtype keyboardSubtype =
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003317 InputMethodUtils.findLastResortApplicableSubtypeLocked(mRes,
3318 InputMethodUtils.getSubtypes(imi),
3319 InputMethodUtils.SUBTYPE_MODE_KEYBOARD, locale, true);
satok4fc87d62011-05-20 16:13:43 +09003320 if (keyboardSubtype != null) {
3321 targetLastImiId = imi.getId();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003322 subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
satok4fc87d62011-05-20 16:13:43 +09003323 imi, keyboardSubtype.hashCode());
3324 if(keyboardSubtype.getLocale().equals(locale)) {
3325 break;
3326 }
3327 }
3328 }
3329 }
3330 }
3331 }
3332
3333 if (!TextUtils.isEmpty(targetLastImiId)) {
3334 if (DEBUG) {
3335 Slog.d(TAG, "Switch to: " + lastImi.getId() + ", " + lastIme.second
3336 + ", from: " + mCurMethodId + ", " + subtypeId);
3337 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003338 setInputMethodWithSubtypeIdLocked(token, targetLastImiId, subtypeId);
satok4fc87d62011-05-20 16:13:43 +09003339 return true;
3340 } else {
3341 return false;
3342 }
satok735cf382010-11-11 20:40:09 +09003343 }
3344 }
3345
Yohei Yukawa70f17e72018-12-09 18:51:38 -08003346 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003347 private boolean switchToNextInputMethod(@NonNull IBinder token, boolean onlyCurrentIme) {
satok688bd472012-02-09 20:09:17 +09003348 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003349 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawaa0755742014-06-04 20:28:18 +09003350 return false;
3351 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003352 final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
Yohei Yukawa136b6ce2018-05-02 10:55:35 -07003353 onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype);
satok688bd472012-02-09 20:09:17 +09003354 if (nextSubtype == null) {
3355 return false;
3356 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003357 setInputMethodWithSubtypeIdLocked(token, nextSubtype.mImi.getId(),
3358 nextSubtype.mSubtypeId);
satok688bd472012-02-09 20:09:17 +09003359 return true;
3360 }
3361 }
3362
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003363 @BinderThread
3364 private boolean shouldOfferSwitchingToNextInputMethod(@NonNull IBinder token) {
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09003365 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003366 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawaa0755742014-06-04 20:28:18 +09003367 return false;
3368 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003369 final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
Yohei Yukawa136b6ce2018-05-02 10:55:35 -07003370 false /* onlyCurrentIme */, mMethodMap.get(mCurMethodId), mCurrentSubtype);
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09003371 if (nextSubtype == null) {
3372 return false;
3373 }
3374 return true;
3375 }
3376 }
3377
3378 @Override
satok68f1b782011-04-11 14:26:04 +09003379 public InputMethodSubtype getLastInputMethodSubtype() {
3380 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003381 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003382 return null;
3383 }
satok68f1b782011-04-11 14:26:04 +09003384 final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
3385 // TODO: Handle the case of the last IME with no subtypes
3386 if (lastIme == null || TextUtils.isEmpty(lastIme.first)
3387 || TextUtils.isEmpty(lastIme.second)) return null;
3388 final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
3389 if (lastImi == null) return null;
3390 try {
Narayan Kamatha09b4d22016-04-15 18:32:45 +01003391 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003392 final int lastSubtypeId =
3393 InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
satok0e7d7d62011-07-05 13:28:06 +09003394 if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
3395 return null;
3396 }
3397 return lastImi.getSubtypeAt(lastSubtypeId);
satok68f1b782011-04-11 14:26:04 +09003398 } catch (NumberFormatException e) {
3399 return null;
3400 }
3401 }
3402 }
3403
satoke7c6998e2011-06-03 17:57:59 +09003404 @Override
satokee5e77c2011-09-02 18:50:15 +09003405 public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
satok91e88122011-07-18 11:11:42 +09003406 // By this IPC call, only a process which shares the same uid with the IME can add
3407 // additional input method subtypes to the IME.
Yohei Yukawa70f5c482016-01-04 19:42:36 -08003408 if (TextUtils.isEmpty(imiId) || subtypes == null) return;
Yohei Yukawab557d572018-12-29 21:26:26 -08003409 final ArrayList<InputMethodSubtype> toBeAdded = new ArrayList<>();
3410 for (InputMethodSubtype subtype : subtypes) {
3411 if (!toBeAdded.contains(subtype)) {
3412 toBeAdded.add(subtype);
3413 } else {
3414 Slog.w(TAG, "Duplicated subtype definition found: "
3415 + subtype.getLocale() + ", " + subtype.getMode());
3416 }
3417 }
satoke7c6998e2011-06-03 17:57:59 +09003418 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003419 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003420 return;
3421 }
Yohei Yukawa79247822017-01-23 15:26:15 -08003422 if (!mSystemReady) {
3423 return;
3424 }
satok91e88122011-07-18 11:11:42 +09003425 final InputMethodInfo imi = mMethodMap.get(imiId);
satokee5e77c2011-09-02 18:50:15 +09003426 if (imi == null) return;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003427 final String[] packageInfos;
3428 try {
3429 packageInfos = mIPackageManager.getPackagesForUid(Binder.getCallingUid());
3430 } catch (RemoteException e) {
3431 Slog.e(TAG, "Failed to get package infos");
3432 return;
3433 }
satok91e88122011-07-18 11:11:42 +09003434 if (packageInfos != null) {
3435 final int packageNum = packageInfos.length;
3436 for (int i = 0; i < packageNum; ++i) {
3437 if (packageInfos[i].equals(imi.getPackageName())) {
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003438 if (subtypes.length > 0) {
Yohei Yukawab557d572018-12-29 21:26:26 -08003439 mAdditionalSubtypeMap.put(imi.getId(), toBeAdded);
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003440 } else {
Yohei Yukawab557d572018-12-29 21:26:26 -08003441 mAdditionalSubtypeMap.remove(imi.getId());
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003442 }
Yohei Yukawab557d572018-12-29 21:26:26 -08003443 AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
3444 mSettings.getCurrentUserId());
satokc5933802011-08-31 21:26:04 +09003445 final long ident = Binder.clearCallingIdentity();
3446 try {
Yohei Yukawa94e33302016-02-12 19:37:03 -08003447 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
satokc5933802011-08-31 21:26:04 +09003448 } finally {
3449 Binder.restoreCallingIdentity(ident);
3450 }
satokee5e77c2011-09-02 18:50:15 +09003451 return;
satok91e88122011-07-18 11:11:42 +09003452 }
3453 }
3454 }
satoke7c6998e2011-06-03 17:57:59 +09003455 }
satokee5e77c2011-09-02 18:50:15 +09003456 return;
satoke7c6998e2011-06-03 17:57:59 +09003457 }
3458
Yohei Yukawab985e6e2018-09-05 17:07:52 -07003459 /**
Austin Wanga63a2c02019-12-19 06:38:19 +00003460 * This is kept due to {@link android.annotation.UnsupportedAppUsage} in
Yohei Yukawab985e6e2018-09-05 17:07:52 -07003461 * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in
3462 * {@link InputMethodService#onCreate()}.
3463 *
3464 * <p>TODO(Bug 113914148): Check if we can remove this.</p>
3465 * @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight()}
3466 */
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09003467 @Override
3468 public int getInputMethodWindowVisibleHeight() {
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003469 // TODO(yukawa): Should we verify the display ID?
lumark90120a82018-08-15 00:33:03 +08003470 return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09003471 }
3472
Yohei Yukawab4f328a2019-05-02 08:41:27 -07003473 @Override
3474 public void reportActivityView(IInputMethodClient parentClient, int childDisplayId,
3475 float[] matrixValues) {
3476 final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(childDisplayId);
3477 if (displayInfo == null) {
3478 throw new IllegalArgumentException(
3479 "Cannot find display for non-existent displayId: " + childDisplayId);
3480 }
3481 final int callingUid = Binder.getCallingUid();
3482 if (callingUid != displayInfo.ownerUid) {
3483 throw new SecurityException("The caller doesn't own the display.");
3484 }
3485
3486 synchronized (mMethodMap) {
3487 final ClientState cs = mClients.get(parentClient.asBinder());
3488 if (cs == null) {
3489 return;
3490 }
3491
3492 // null matrixValues means that the entry needs to be removed.
3493 if (matrixValues == null) {
3494 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(childDisplayId);
3495 if (info == null) {
3496 return;
3497 }
3498 if (info.mParentClient != cs) {
3499 throw new SecurityException("Only the owner client can clear"
3500 + " ActivityViewGeometry for display #" + childDisplayId);
3501 }
3502 mActivityViewDisplayIdToParentMap.remove(childDisplayId);
3503 return;
3504 }
3505
3506 ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(childDisplayId);
3507 if (info != null && info.mParentClient != cs) {
3508 throw new InvalidParameterException("Display #" + childDisplayId
3509 + " is already registered by " + info.mParentClient);
3510 }
3511 if (info == null) {
3512 if (!mWindowManagerInternal.isUidAllowedOnDisplay(childDisplayId, cs.uid)) {
3513 throw new SecurityException(cs + " cannot access to display #"
3514 + childDisplayId);
3515 }
3516 info = new ActivityViewInfo(cs, new Matrix());
3517 mActivityViewDisplayIdToParentMap.put(childDisplayId, info);
3518 }
3519 info.mMatrix.setValues(matrixValues);
3520
3521 if (mCurClient == null || mCurClient.curSession == null) {
3522 return;
3523 }
3524
3525 Matrix matrix = null;
3526 int displayId = mCurClient.selfReportedDisplayId;
3527 boolean needToNotify = false;
3528 while (true) {
3529 needToNotify |= (displayId == childDisplayId);
3530 final ActivityViewInfo next = mActivityViewDisplayIdToParentMap.get(displayId);
3531 if (next == null) {
3532 break;
3533 }
3534 if (matrix == null) {
3535 matrix = new Matrix(next.mMatrix);
3536 } else {
3537 matrix.postConcat(next.mMatrix);
3538 }
3539 if (next.mParentClient.selfReportedDisplayId == mCurTokenDisplayId) {
3540 if (needToNotify) {
3541 final float[] values = new float[9];
3542 matrix.getValues(values);
3543 try {
3544 mCurClient.client.updateActivityViewToScreenMatrix(mCurSeq, values);
3545 } catch (RemoteException e) {
3546 }
3547 }
3548 break;
3549 }
3550 displayId = info.mParentClient.selfReportedDisplayId;
3551 }
3552 }
3553 }
3554
Yohei Yukawac54c1172018-09-06 11:39:50 -07003555 @BinderThread
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003556 private void notifyUserAction(@NonNull IBinder token) {
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003557 if (DEBUG) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003558 Slog.d(TAG, "Got the notification of a user action.");
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003559 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003560 synchronized (mMethodMap) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003561 if (mCurToken != token) {
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09003562 if (DEBUG) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003563 Slog.d(TAG, "Ignoring the user action notification from IMEs that are no longer"
3564 + " active.");
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09003565 }
3566 return;
3567 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003568 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
3569 if (imi != null) {
Yohei Yukawa02970512014-06-05 16:16:18 +09003570 mSwitchingController.onUserActionLocked(imi, mCurrentSubtype);
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003571 }
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003572 }
3573 }
3574
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003575 @BinderThread
3576 private void reportPreRendered(IBinder token, EditorInfo info) {
3577 synchronized (mMethodMap) {
3578 if (!calledWithValidTokenLocked(token)) {
3579 return;
3580 }
3581 if (mCurClient != null && mCurClient.client != null) {
3582 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
3583 MSG_REPORT_PRE_RENDERED, info, mCurClient));
3584 }
3585 }
3586 }
3587
3588 @BinderThread
3589 private void applyImeVisibility(IBinder token, boolean setVisible) {
3590 synchronized (mMethodMap) {
3591 if (!calledWithValidTokenLocked(token)) {
3592 return;
3593 }
Tarandeep Singh500a38f2019-09-26 13:36:40 -07003594 if (!setVisible) {
Taran Singhd7fc5862019-10-10 14:45:17 +02003595 if (mCurClient != null) {
3596 // IMMS only knows of focused window, not the actual IME target.
3597 // e.g. it isn't aware of any window that has both
3598 // NOT_FOCUSABLE, ALT_FOCUSABLE_IM flags set and can the IME target.
3599 // Send it to window manager to hide IME from IME target window.
3600 // TODO(b/139861270): send to mCurClient.client once IMMS is aware of
3601 // actual IME target.
3602 mWindowManagerInternal.hideIme(mCurClient.selfReportedDisplayId);
Tarandeep Singh500a38f2019-09-26 13:36:40 -07003603 }
3604 } else {
3605 // Send to window manager to show IME after IME layout finishes.
3606 mWindowManagerInternal.showImePostLayout(mLastImeTargetWindow);
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003607 }
3608 }
3609 }
3610
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003611 private void setInputMethodWithSubtypeIdLocked(IBinder token, String id, int subtypeId) {
3612 if (token == null) {
3613 if (mContext.checkCallingOrSelfPermission(
3614 android.Manifest.permission.WRITE_SECURE_SETTINGS)
3615 != PackageManager.PERMISSION_GRANTED) {
3616 throw new SecurityException(
3617 "Using null token requires permission "
3618 + android.Manifest.permission.WRITE_SECURE_SETTINGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003619 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003620 } else if (mCurToken != token) {
3621 Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
3622 + " token: " + token);
3623 return;
3624 }
3625
3626 final long ident = Binder.clearCallingIdentity();
3627 try {
3628 setInputMethodLocked(id, subtypeId);
3629 } finally {
3630 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003631 }
3632 }
3633
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003634 @BinderThread
3635 private void hideMySoftInput(@NonNull IBinder token, int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003636 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003637 if (!calledWithValidTokenLocked(token)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003638 return;
3639 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003640 long ident = Binder.clearCallingIdentity();
3641 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003642 hideCurrentInputLocked(flags, null);
3643 } finally {
3644 Binder.restoreCallingIdentity(ident);
3645 }
3646 }
3647 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003648
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003649 @BinderThread
3650 private void showMySoftInput(@NonNull IBinder token, int flags) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003651 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003652 if (!calledWithValidTokenLocked(token)) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003653 return;
3654 }
3655 long ident = Binder.clearCallingIdentity();
3656 try {
3657 showCurrentInputLocked(flags, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003658 } finally {
3659 Binder.restoreCallingIdentity(ident);
3660 }
3661 }
3662 }
3663
3664 void setEnabledSessionInMainThread(SessionState session) {
3665 if (mEnabledSession != session) {
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003666 if (mEnabledSession != null && mEnabledSession.session != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003667 try {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003668 if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003669 mEnabledSession.method.setSessionEnabled(mEnabledSession.session, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003670 } catch (RemoteException e) {
3671 }
3672 }
3673 mEnabledSession = session;
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003674 if (mEnabledSession != null && mEnabledSession.session != null) {
3675 try {
3676 if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
3677 mEnabledSession.method.setSessionEnabled(mEnabledSession.session, true);
3678 } catch (RemoteException e) {
3679 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003680 }
3681 }
3682 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003683
Yohei Yukawa930328c2017-10-18 20:19:53 -07003684 @MainThread
satok42c5a162011-05-26 16:46:14 +09003685 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003686 public boolean handleMessage(Message msg) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003687 SomeArgs args;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003688 switch (msg.what) {
satokab751aa2010-09-14 19:17:36 +09003689 case MSG_SHOW_IM_SUBTYPE_PICKER:
Seigo Nonaka14e13912015-05-06 21:04:13 -07003690 final boolean showAuxSubtypes;
lumark0b05f9e2018-11-26 15:09:06 +08003691 final int displayId = msg.arg2;
Seigo Nonaka14e13912015-05-06 21:04:13 -07003692 switch (msg.arg1) {
3693 case InputMethodManager.SHOW_IM_PICKER_MODE_AUTO:
3694 // This is undocumented so far, but IMM#showInputMethodPicker() has been
3695 // implemented so that auxiliary subtypes will be excluded when the soft
3696 // keyboard is invisible.
3697 showAuxSubtypes = mInputShown;
3698 break;
3699 case InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES:
3700 showAuxSubtypes = true;
3701 break;
3702 case InputMethodManager.SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES:
3703 showAuxSubtypes = false;
3704 break;
3705 default:
3706 Slog.e(TAG, "Unknown subtype picker mode = " + msg.arg1);
3707 return false;
3708 }
lumark0b05f9e2018-11-26 15:09:06 +08003709 showInputMethodMenu(showAuxSubtypes, displayId);
satokab751aa2010-09-14 19:17:36 +09003710 return true;
3711
satok47a44912010-10-06 16:03:58 +09003712 case MSG_SHOW_IM_SUBTYPE_ENABLER:
Yohei Yukawa41f34272015-12-14 15:41:52 -08003713 showInputMethodAndSubtypeEnabler((String)msg.obj);
satok217f5482010-12-15 05:19:19 +09003714 return true;
3715
3716 case MSG_SHOW_IM_CONFIG:
3717 showConfigureInputMethods();
satok47a44912010-10-06 16:03:58 +09003718 return true;
3719
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003720 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003721
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003722 case MSG_UNBIND_INPUT:
3723 try {
3724 ((IInputMethod)msg.obj).unbindInput();
3725 } catch (RemoteException e) {
3726 // There is nothing interesting about the method dying.
3727 }
3728 return true;
3729 case MSG_BIND_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003730 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003731 try {
3732 ((IInputMethod)args.arg1).bindInput((InputBinding)args.arg2);
3733 } catch (RemoteException e) {
3734 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003735 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003736 return true;
3737 case MSG_SHOW_SOFT_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003738 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003739 try {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003740 if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput("
Craig Mautner6efb4c72013-03-13 10:17:41 -07003741 + msg.arg1 + ", " + args.arg2 + ")");
Craig Mautnerca0ac712013-03-14 09:43:02 -07003742 ((IInputMethod)args.arg1).showSoftInput(msg.arg1, (ResultReceiver)args.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003743 } catch (RemoteException e) {
3744 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003745 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003746 return true;
3747 case MSG_HIDE_SOFT_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003748 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003749 try {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003750 if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, "
Craig Mautner6efb4c72013-03-13 10:17:41 -07003751 + args.arg2 + ")");
Craig Mautnerca0ac712013-03-14 09:43:02 -07003752 ((IInputMethod)args.arg1).hideSoftInput(0, (ResultReceiver)args.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003753 } catch (RemoteException e) {
3754 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003755 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003756 return true;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07003757 case MSG_HIDE_CURRENT_INPUT_METHOD:
3758 synchronized (mMethodMap) {
3759 hideCurrentInputLocked(0, null);
3760 }
3761 return true;
Yohei Yukawac54c1172018-09-06 11:39:50 -07003762 case MSG_INITIALIZE_IME:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003763 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003764 try {
lumark90120a82018-08-15 00:33:03 +08003765 if (DEBUG) {
3766 Slog.v(TAG, "Sending attach of token: " + args.arg2 + " for display: "
3767 + msg.arg1);
3768 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07003769 final IBinder token = (IBinder) args.arg2;
lumark90120a82018-08-15 00:33:03 +08003770 ((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
Yohei Yukawac54c1172018-09-06 11:39:50 -07003771 new InputMethodPrivilegedOperationsImpl(this, token));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003772 } catch (RemoteException e) {
3773 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003774 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003775 return true;
Jeff Brownc28867a2013-03-26 15:42:39 -07003776 case MSG_CREATE_SESSION: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003777 args = (SomeArgs)msg.obj;
Jeff Brown1951ce82013-04-04 22:45:12 -07003778 IInputMethod method = (IInputMethod)args.arg1;
Jeff Brownc28867a2013-03-26 15:42:39 -07003779 InputChannel channel = (InputChannel)args.arg2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003780 try {
Jeff Brown1951ce82013-04-04 22:45:12 -07003781 method.createSession(channel, (IInputSessionCallback)args.arg3);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003782 } catch (RemoteException e) {
Jeff Brownc28867a2013-03-26 15:42:39 -07003783 } finally {
Jeff Brown1951ce82013-04-04 22:45:12 -07003784 // Dispose the channel if the input method is not local to this process
3785 // because the remote proxy will get its own copy when unparceled.
3786 if (channel != null && Binder.isProxy(method)) {
Jeff Brownc28867a2013-03-26 15:42:39 -07003787 channel.dispose();
3788 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003789 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003790 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003791 return true;
Jeff Brownc28867a2013-03-26 15:42:39 -07003792 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003793 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003794
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003795 case MSG_START_INPUT: {
Yohei Yukawaf7526b52017-02-11 20:57:10 -08003796 final int missingMethods = msg.arg1;
3797 final boolean restarting = msg.arg2 != 0;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003798 args = (SomeArgs) msg.obj;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08003799 final IBinder startInputToken = (IBinder) args.arg1;
3800 final SessionState session = (SessionState) args.arg2;
3801 final IInputContext inputContext = (IInputContext) args.arg3;
3802 final EditorInfo editorInfo = (EditorInfo) args.arg4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003803 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003804 setEnabledSessionInMainThread(session);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08003805 session.method.startInput(startInputToken, inputContext, missingMethods,
Tarandeep Singheadb1392018-11-09 18:15:57 +01003806 editorInfo, restarting, session.client.shouldPreRenderIme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003807 } catch (RemoteException e) {
3808 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003809 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003810 return true;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003811 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003812
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003813 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003814
Yohei Yukawa33e81792015-11-17 21:14:42 -08003815 case MSG_UNBIND_CLIENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003816 try {
Yohei Yukawa33e81792015-11-17 21:14:42 -08003817 ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003818 } catch (RemoteException e) {
3819 // There is nothing interesting about the last client dying.
3820 }
3821 return true;
Yohei Yukawa33e81792015-11-17 21:14:42 -08003822 case MSG_BIND_CLIENT: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003823 args = (SomeArgs)msg.obj;
Jeff Brown1951ce82013-04-04 22:45:12 -07003824 IInputMethodClient client = (IInputMethodClient)args.arg1;
3825 InputBindResult res = (InputBindResult)args.arg2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003826 try {
Jeff Brown1951ce82013-04-04 22:45:12 -07003827 client.onBindMethod(res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003828 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003829 Slog.w(TAG, "Client died receiving input method " + args.arg2);
Jeff Brown1951ce82013-04-04 22:45:12 -07003830 } finally {
3831 // Dispose the channel if the input method is not local to this process
3832 // because the remote proxy will get its own copy when unparceled.
3833 if (res.channel != null && Binder.isProxy(client)) {
3834 res.channel.dispose();
3835 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003836 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003837 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003838 return true;
Jeff Brown1951ce82013-04-04 22:45:12 -07003839 }
Dianne Hackborna6e41342012-05-22 16:30:34 -07003840 case MSG_SET_ACTIVE:
3841 try {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003842 ((ClientState)msg.obj).client.setActive(msg.arg1 != 0, msg.arg2 != 0);
Dianne Hackborna6e41342012-05-22 16:30:34 -07003843 } catch (RemoteException e) {
3844 Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
3845 + ((ClientState)msg.obj).pid + " uid "
3846 + ((ClientState)msg.obj).uid);
3847 }
3848 return true;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003849 case MSG_SET_INTERACTIVE:
3850 handleSetInteractive(msg.arg1 != 0);
3851 return true;
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003852 case MSG_REPORT_FULLSCREEN_MODE: {
3853 final boolean fullscreen = msg.arg1 != 0;
3854 final ClientState clientState = (ClientState)msg.obj;
3855 try {
3856 clientState.client.reportFullscreenMode(fullscreen);
3857 } catch (RemoteException e) {
3858 Slog.w(TAG, "Got RemoteException sending "
3859 + "reportFullscreen(" + fullscreen + ") notification to pid="
3860 + clientState.pid + " uid=" + clientState.uid);
3861 }
3862 return true;
3863 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003864 case MSG_REPORT_PRE_RENDERED: {
3865 args = (SomeArgs) msg.obj;
3866 final EditorInfo info = (EditorInfo) args.arg1;
3867 final ClientState clientState = (ClientState) args.arg2;
3868 try {
3869 clientState.client.reportPreRendered(info);
3870 } catch (RemoteException e) {
3871 Slog.w(TAG, "Got RemoteException sending "
3872 + "reportPreRendered(" + info + ") notification to pid="
3873 + clientState.pid + " uid=" + clientState.uid);
3874 }
3875 args.recycle();
3876 return true;
3877 }
3878 case MSG_APPLY_IME_VISIBILITY: {
3879 final boolean setVisible = msg.arg1 != 0;
3880 final ClientState clientState = (ClientState) msg.obj;
3881 try {
3882 clientState.client.applyImeVisibility(setVisible);
3883 } catch (RemoteException e) {
3884 Slog.w(TAG, "Got RemoteException sending "
3885 + "applyImeVisibility(" + setVisible + ") notification to pid="
3886 + clientState.pid + " uid=" + clientState.uid);
3887 }
3888 return true;
3889 }
satok01038492012-04-09 21:08:27 +09003890
3891 // --------------------------------------------------------------
3892 case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
Michael Wright7b5a96b2014-08-09 19:28:42 -07003893 mHardKeyboardListener.handleHardKeyboardStatusChange(msg.arg1 == 1);
satok01038492012-04-09 21:08:27 +09003894 return true;
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07003895 case MSG_SYSTEM_UNLOCK_USER:
3896 final int userId = msg.arg1;
3897 onUnlockUser(userId);
3898 return true;
Adam Hebc67f2e2019-11-13 14:34:56 -08003899
3900 // ---------------------------------------------------------------
3901 case MSG_INLINE_SUGGESTIONS_REQUEST:
3902 args = (SomeArgs) msg.obj;
3903 final ComponentName componentName = (ComponentName) args.arg2;
3904 final AutofillId autofillId = (AutofillId) args.arg3;
3905 final IInlineSuggestionsRequestCallback callback =
3906 (IInlineSuggestionsRequestCallback) args.arg4;
3907 try {
3908 ((IInputMethod) args.arg1).onCreateInlineSuggestionsRequest(componentName,
3909 autofillId, callback);
3910 } catch (RemoteException e) {
3911 Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
3912 }
3913 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003914 }
3915 return false;
3916 }
3917
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003918 private void handleSetInteractive(final boolean interactive) {
3919 synchronized (mMethodMap) {
3920 mIsInteractive = interactive;
Yohei Yukawa849443c2019-01-21 09:02:25 -08003921 updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003922
3923 // Inform the current client of the change in active status
3924 if (mCurClient != null && mCurClient.client != null) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003925 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
3926 MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mInFullscreenMode ? 1 : 0,
3927 mCurClient));
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003928 }
3929 }
3930 }
3931
satokdc9ddae2011-10-06 12:22:36 +09003932 private boolean chooseNewDefaultIMELocked() {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003933 final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
3934 mSettings.getEnabledInputMethodListLocked());
satokdc9ddae2011-10-06 12:22:36 +09003935 if (imi != null) {
satok03eb319a2010-11-11 18:17:42 +09003936 if (DEBUG) {
3937 Slog.d(TAG, "New default IME was selected: " + imi.getId());
3938 }
satok723a27e2010-11-11 14:58:11 +09003939 resetSelectedInputMethodAndSubtypeLocked(imi.getId());
Brandon Ballinger6da35a02009-10-21 00:38:13 -07003940 return true;
3941 }
3942
3943 return false;
3944 }
3945
Yohei Yukawa05139322018-12-25 10:34:14 -08003946 static void queryInputMethodServicesInternal(Context context,
3947 @UserIdInt int userId, ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap,
3948 ArrayMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList) {
3949 methodList.clear();
3950 methodMap.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003951
Yohei Yukawaed4952a2016-02-17 07:57:25 -08003952 // Note: We do not specify PackageManager.MATCH_ENCRYPTION_* flags here because the default
3953 // behavior of PackageManager is exactly what we want. It by default picks up appropriate
3954 // services depending on the unlock state for the specified user.
Yohei Yukawa05139322018-12-25 10:34:14 -08003955 final List<ResolveInfo> services = context.getPackageManager().queryIntentServicesAsUser(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003956 new Intent(InputMethod.SERVICE_INTERFACE),
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08003957 PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS,
Yohei Yukawa05139322018-12-25 10:34:14 -08003958 userId);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003959
Yohei Yukawa05139322018-12-25 10:34:14 -08003960 methodList.ensureCapacity(services.size());
3961 methodMap.ensureCapacity(services.size());
3962
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003963 for (int i = 0; i < services.size(); ++i) {
3964 ResolveInfo ri = services.get(i);
3965 ServiceInfo si = ri.serviceInfo;
Yohei Yukawaddad4b92017-02-02 01:46:13 -08003966 final String imeId = InputMethodInfo.computeId(ri);
3967 if (!android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
3968 Slog.w(TAG, "Skipping input method " + imeId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003969 + ": it does not require the permission "
3970 + android.Manifest.permission.BIND_INPUT_METHOD);
3971 continue;
3972 }
3973
Yohei Yukawaddad4b92017-02-02 01:46:13 -08003974 if (DEBUG) Slog.d(TAG, "Checking " + imeId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003975
3976 try {
Yohei Yukawa05139322018-12-25 10:34:14 -08003977 final InputMethodInfo imi = new InputMethodInfo(context, ri,
3978 additionalSubtypeMap.get(imeId));
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08003979 if (imi.isVrOnly()) {
3980 continue; // Skip VR-only IME, which isn't supported for now.
3981 }
Yohei Yukawa05139322018-12-25 10:34:14 -08003982 methodList.add(imi);
3983 methodMap.put(imi.getId(), imi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003984 if (DEBUG) {
Yohei Yukawa05139322018-12-25 10:34:14 -08003985 Slog.d(TAG, "Found an input method " + imi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003986 }
Tadashi G. Takaoka3c23d5b2016-09-16 11:41:07 +09003987 } catch (Exception e) {
Yohei Yukawaddad4b92017-02-02 01:46:13 -08003988 Slog.wtf(TAG, "Unable to load input method " + imeId, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003989 }
3990 }
Yohei Yukawa05139322018-12-25 10:34:14 -08003991 }
3992
3993 @GuardedBy("mMethodMap")
3994 void buildInputMethodListLocked(boolean resetDefaultEnabledIme) {
3995 if (DEBUG) {
3996 Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
3997 + " \n ------ caller=" + Debug.getCallers(10));
3998 }
3999 if (!mSystemReady) {
4000 Slog.e(TAG, "buildInputMethodListLocked is not allowed until system is ready");
4001 return;
4002 }
4003 mMethodMapUpdateCount++;
4004 mMyPackageMonitor.clearKnownImePackageNamesLocked();
4005
4006 queryInputMethodServicesInternal(mContext, mSettings.getCurrentUserId(),
Yohei Yukawab557d572018-12-29 21:26:26 -08004007 mAdditionalSubtypeMap, mMethodMap, mMethodList);
Brandon Ballinger6da35a02009-10-21 00:38:13 -07004008
Yohei Yukawac4e44912017-02-09 19:30:22 -08004009 // Construct the set of possible IME packages for onPackageChanged() to avoid false
4010 // negatives when the package state remains to be the same but only the component state is
4011 // changed.
4012 {
4013 // Here we intentionally use PackageManager.MATCH_DISABLED_COMPONENTS since the purpose
4014 // of this query is to avoid false negatives. PackageManager.MATCH_ALL could be more
4015 // conservative, but it seems we cannot use it for now (Issue 35176630).
Yohei Yukawa05139322018-12-25 10:34:14 -08004016 final List<ResolveInfo> allInputMethodServices =
4017 mContext.getPackageManager().queryIntentServicesAsUser(
4018 new Intent(InputMethod.SERVICE_INTERFACE),
4019 PackageManager.MATCH_DISABLED_COMPONENTS, mSettings.getCurrentUserId());
Yohei Yukawac4e44912017-02-09 19:30:22 -08004020 final int N = allInputMethodServices.size();
4021 for (int i = 0; i < N; ++i) {
4022 final ServiceInfo si = allInputMethodServices.get(i).serviceInfo;
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08004023 if (android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
4024 mMyPackageMonitor.addKnownImePackageNameLocked(si.packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08004025 }
Yohei Yukawac4e44912017-02-09 19:30:22 -08004026 }
4027 }
4028
Yohei Yukawa9c372192018-03-20 22:54:56 -07004029 boolean reenableMinimumNonAuxSystemImes = false;
Yohei Yukawa859df052016-02-17 07:56:46 -08004030 // TODO: The following code should find better place to live.
4031 if (!resetDefaultEnabledIme) {
4032 boolean enabledImeFound = false;
Yohei Yukawa9c372192018-03-20 22:54:56 -07004033 boolean enabledNonAuxImeFound = false;
Yohei Yukawa859df052016-02-17 07:56:46 -08004034 final List<InputMethodInfo> enabledImes = mSettings.getEnabledInputMethodListLocked();
4035 final int N = enabledImes.size();
4036 for (int i = 0; i < N; ++i) {
4037 final InputMethodInfo imi = enabledImes.get(i);
4038 if (mMethodList.contains(imi)) {
4039 enabledImeFound = true;
Yohei Yukawa9c372192018-03-20 22:54:56 -07004040 if (!imi.isAuxiliaryIme()) {
4041 enabledNonAuxImeFound = true;
4042 break;
4043 }
Yohei Yukawa859df052016-02-17 07:56:46 -08004044 }
4045 }
4046 if (!enabledImeFound) {
Yohei Yukawad0332832017-02-01 13:59:43 -08004047 if (DEBUG) {
4048 Slog.i(TAG, "All the enabled IMEs are gone. Reset default enabled IMEs.");
4049 }
Yohei Yukawa859df052016-02-17 07:56:46 -08004050 resetDefaultEnabledIme = true;
4051 resetSelectedInputMethodAndSubtypeLocked("");
Yohei Yukawa9c372192018-03-20 22:54:56 -07004052 } else if (!enabledNonAuxImeFound) {
4053 if (DEBUG) {
4054 Slog.i(TAG, "All the enabled non-Aux IMEs are gone. Do partial reset.");
4055 }
4056 reenableMinimumNonAuxSystemImes = true;
Yohei Yukawa859df052016-02-17 07:56:46 -08004057 }
4058 }
4059
Yohei Yukawa9c372192018-03-20 22:54:56 -07004060 if (resetDefaultEnabledIme || reenableMinimumNonAuxSystemImes) {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09004061 final ArrayList<InputMethodInfo> defaultEnabledIme =
Yohei Yukawa9c372192018-03-20 22:54:56 -07004062 InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList,
4063 reenableMinimumNonAuxSystemImes);
Yohei Yukawa68645a62016-02-17 07:54:20 -08004064 final int N = defaultEnabledIme.size();
4065 for (int i = 0; i < N; ++i) {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09004066 final InputMethodInfo imi = defaultEnabledIme.get(i);
4067 if (DEBUG) {
4068 Slog.d(TAG, "--- enable ime = " + imi);
4069 }
4070 setInputMethodEnabledLocked(imi.getId(), true);
4071 }
4072 }
4073
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004074 final String defaultImiId = mSettings.getSelectedInputMethod();
satok0a1bcf42012-05-16 19:26:31 +09004075 if (!TextUtils.isEmpty(defaultImiId)) {
Yohei Yukawa94e33302016-02-12 19:37:03 -08004076 if (!mMethodMap.containsKey(defaultImiId)) {
satok0a1bcf42012-05-16 19:26:31 +09004077 Slog.w(TAG, "Default IME is uninstalled. Choose new default IME.");
4078 if (chooseNewDefaultIMELocked()) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07004079 updateInputMethodsFromSettingsLocked(true);
satok0a1bcf42012-05-16 19:26:31 +09004080 }
4081 } else {
4082 // Double check that the default IME is certainly enabled.
4083 setInputMethodEnabledLocked(defaultImiId, true);
Brandon Ballinger6da35a02009-10-21 00:38:13 -07004084 }
4085 }
Yohei Yukawa3d46bab2014-05-30 18:10:18 +09004086 // Here is not the perfect place to reset the switching controller. Ideally
4087 // mSwitchingController and mSettings should be able to share the same state.
4088 // TODO: Make sure that mSwitchingController and mSettings are sharing the
4089 // the same enabled IMEs list.
Yohei Yukawac834a252014-05-21 22:42:32 +09004090 mSwitchingController.resetCircularListLocked(mContext);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004091 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004093 // ----------------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004094
satok217f5482010-12-15 05:19:19 +09004095 private void showInputMethodAndSubtypeEnabler(String inputMethodId) {
Tadashi G. Takaokaf49688f2011-01-20 17:56:13 +09004096 Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
satok47a44912010-10-06 16:03:58 +09004097 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
satok86417ea2010-10-27 14:11:03 +09004098 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
4099 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
satok7fee71f2010-12-17 18:54:26 +09004100 if (!TextUtils.isEmpty(inputMethodId)) {
Tadashi G. Takaoka25480202011-01-20 23:13:02 +09004101 intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
satok7fee71f2010-12-17 18:54:26 +09004102 }
Yohei Yukawa41f34272015-12-14 15:41:52 -08004103 final int userId;
4104 synchronized (mMethodMap) {
4105 userId = mSettings.getCurrentUserId();
4106 }
4107 mContext.startActivityAsUser(intent, null, UserHandle.of(userId));
satok217f5482010-12-15 05:19:19 +09004108 }
4109
4110 private void showConfigureInputMethods() {
4111 Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
4112 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
4113 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
4114 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Satoshi Kataoka3ba439d2012-10-05 18:30:13 +09004115 mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
satok47a44912010-10-06 16:03:58 +09004116 }
4117
satok2c93efc2012-04-02 19:33:47 +09004118 private boolean isScreenLocked() {
4119 return mKeyguardManager != null
4120 && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure();
4121 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004122
lumark0b05f9e2018-11-26 15:09:06 +08004123 private void showInputMethodMenu(boolean showAuxSubtypes, int displayId) {
Seigo Nonaka14e13912015-05-06 21:04:13 -07004124 if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004125
satok2c93efc2012-04-02 19:33:47 +09004126 final boolean isScreenLocked = isScreenLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004127
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004128 final String lastInputMethodId = mSettings.getSelectedInputMethod();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004129 int lastInputMethodSubtypeId = mSettings.getSelectedInputMethodSubtypeId(lastInputMethodId);
Joe Onorato8a9b2202010-02-26 18:56:32 -08004130 if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004131
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004132 synchronized (mMethodMap) {
Yohei Yukawacf3bbff2018-11-20 17:24:20 -08004133 final List<ImeSubtypeListItem> imList =
4134 mSwitchingController.getSortedInputMethodAndSubtypeListLocked(
4135 showAuxSubtypes, isScreenLocked);
4136 if (imList.isEmpty()) {
satok7f35c8c2010-10-07 21:13:11 +09004137 return;
4138 }
4139
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004140 hideInputMethodMenuLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004141
satokc3690562012-01-10 20:14:43 +09004142 if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004143 final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtypeLocked();
satokc3690562012-01-10 20:14:43 +09004144 if (currentSubtype != null) {
4145 final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004146 lastInputMethodSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
4147 currentImi, currentSubtype.hashCode());
satokc3690562012-01-10 20:14:43 +09004148 }
4149 }
4150
Ken Wakasa761eb372011-03-04 19:06:18 +09004151 final int N = imList.size();
satokab751aa2010-09-14 19:17:36 +09004152 mIms = new InputMethodInfo[N];
4153 mSubtypeIds = new int[N];
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004154 int checkedItem = 0;
4155 for (int i = 0; i < N; ++i) {
Ken Wakasa05dbb652011-08-22 15:22:43 +09004156 final ImeSubtypeListItem item = imList.get(i);
4157 mIms[i] = item.mImi;
4158 mSubtypeIds[i] = item.mSubtypeId;
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004159 if (mIms[i].getId().equals(lastInputMethodId)) {
satokab751aa2010-09-14 19:17:36 +09004160 int subtypeId = mSubtypeIds[i];
4161 if ((subtypeId == NOT_A_SUBTYPE_ID)
4162 || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0)
4163 || (subtypeId == lastInputMethodSubtypeId)) {
4164 checkedItem = i;
4165 }
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004166 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004167 }
Alan Viverette505e3ab2014-11-24 15:22:11 -08004168
lumark0b05f9e2018-11-26 15:09:06 +08004169 final ActivityThread currentThread = ActivityThread.currentActivityThread();
Andrew Sapperstein8a3b4cb2017-04-28 14:35:31 -07004170 final Context settingsContext = new ContextThemeWrapper(
lumark0b05f9e2018-11-26 15:09:06 +08004171 displayId == DEFAULT_DISPLAY ? currentThread.getSystemUiContext()
4172 : currentThread.createSystemUiContext(displayId),
Alan Viverette505e3ab2014-11-24 15:22:11 -08004173 com.android.internal.R.style.Theme_DeviceDefault_Settings);
4174
4175 mDialogBuilder = new AlertDialog.Builder(settingsContext);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004176 mDialogBuilder.setOnCancelListener(new OnCancelListener() {
4177 @Override
4178 public void onCancel(DialogInterface dialog) {
4179 hideInputMethodMenu();
4180 }
4181 });
Alan Viverette505e3ab2014-11-24 15:22:11 -08004182
4183 final Context dialogContext = mDialogBuilder.getContext();
4184 final TypedArray a = dialogContext.obtainStyledAttributes(null,
4185 com.android.internal.R.styleable.DialogPreference,
4186 com.android.internal.R.attr.alertDialogStyle, 0);
4187 final Drawable dialogIcon = a.getDrawable(
4188 com.android.internal.R.styleable.DialogPreference_dialogIcon);
4189 a.recycle();
4190
4191 mDialogBuilder.setIcon(dialogIcon);
4192
Yohei Yukawad34e1482016-02-11 08:03:52 -08004193 final LayoutInflater inflater = dialogContext.getSystemService(LayoutInflater.class);
satok01038492012-04-09 21:08:27 +09004194 final View tv = inflater.inflate(
4195 com.android.internal.R.layout.input_method_switch_dialog_title, null);
4196 mDialogBuilder.setCustomTitle(tv);
4197
4198 // Setup layout for a toggle switch of the hardware keyboard
4199 mSwitchingDialogTitleView = tv;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004200 mSwitchingDialogTitleView
4201 .findViewById(com.android.internal.R.id.hard_keyboard_section)
Seigo Nonaka7309b122015-08-17 18:34:13 -07004202 .setVisibility(mWindowManagerInternal.isHardKeyboardAvailable()
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004203 ? View.VISIBLE : View.GONE);
Alan Viverette505e3ab2014-11-24 15:22:11 -08004204 final Switch hardKeySwitch = (Switch) mSwitchingDialogTitleView.findViewById(
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004205 com.android.internal.R.id.hard_keyboard_switch);
Michael Wright7b5a96b2014-08-09 19:28:42 -07004206 hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004207 hardKeySwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
4208 @Override
4209 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07004210 mSettings.setShowImeWithHardKeyboard(isChecked);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004211 // Ensure that the input method dialog is dismissed when changing
4212 // the hardware keyboard state.
4213 hideInputMethodMenu();
4214 }
4215 });
4216
Alan Viverette505e3ab2014-11-24 15:22:11 -08004217 final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(dialogContext,
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004218 com.android.internal.R.layout.input_method_switch_item, imList, checkedItem);
4219 final OnClickListener choiceListener = new OnClickListener() {
4220 @Override
4221 public void onClick(final DialogInterface dialog, final int which) {
4222 synchronized (mMethodMap) {
4223 if (mIms == null || mIms.length <= which || mSubtypeIds == null
4224 || mSubtypeIds.length <= which) {
4225 return;
satok01038492012-04-09 21:08:27 +09004226 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004227 final InputMethodInfo im = mIms[which];
4228 int subtypeId = mSubtypeIds[which];
4229 adapter.mCheckedItem = which;
4230 adapter.notifyDataSetChanged();
4231 hideInputMethodMenu();
4232 if (im != null) {
4233 if (subtypeId < 0 || subtypeId >= im.getSubtypeCount()) {
4234 subtypeId = NOT_A_SUBTYPE_ID;
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08004235 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004236 setInputMethodLocked(im.getId(), subtypeId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004237 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004238 }
4239 }
4240 };
4241 mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004243 mSwitchingDialog = mDialogBuilder.create();
Dianne Hackborne3a7f622011-03-03 21:48:24 -08004244 mSwitchingDialog.setCanceledOnTouchOutside(true);
Wale Ogunwale3a931692016-11-02 16:49:48 -07004245 final Window w = mSwitchingDialog.getWindow();
Yohei Yukawa6e875592019-01-28 00:49:30 -08004246 final LayoutParams attrs = w.getAttributes();
4247 w.setType(LayoutParams.TYPE_INPUT_METHOD_DIALOG);
Wale Ogunwale3a931692016-11-02 16:49:48 -07004248 // Use an alternate token for the dialog for that window manager can group the token
4249 // with other IME windows based on type vs. grouping based on whichever token happens
4250 // to get selected by the system later on.
4251 attrs.token = mSwitchingDialogToken;
Roshan Piusa3f89c62019-10-11 08:50:53 -07004252 attrs.privateFlags |= LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
Wale Ogunwale3a931692016-11-02 16:49:48 -07004253 attrs.setTitle("Select input method");
4254 w.setAttributes(attrs);
Yohei Yukawa849443c2019-01-21 09:02:25 -08004255 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004256 mSwitchingDialog.show();
4257 }
4258 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004259
Ken Wakasa05dbb652011-08-22 15:22:43 +09004260 private static class ImeSubtypeListAdapter extends ArrayAdapter<ImeSubtypeListItem> {
4261 private final LayoutInflater mInflater;
4262 private final int mTextViewResourceId;
4263 private final List<ImeSubtypeListItem> mItemsList;
Satoshi Kataokad2142962012-11-12 18:43:06 +09004264 public int mCheckedItem;
Ken Wakasa05dbb652011-08-22 15:22:43 +09004265 public ImeSubtypeListAdapter(Context context, int textViewResourceId,
4266 List<ImeSubtypeListItem> itemsList, int checkedItem) {
4267 super(context, textViewResourceId, itemsList);
Alan Viverette505e3ab2014-11-24 15:22:11 -08004268
Ken Wakasa05dbb652011-08-22 15:22:43 +09004269 mTextViewResourceId = textViewResourceId;
4270 mItemsList = itemsList;
4271 mCheckedItem = checkedItem;
Yohei Yukawad34e1482016-02-11 08:03:52 -08004272 mInflater = context.getSystemService(LayoutInflater.class);
Ken Wakasa05dbb652011-08-22 15:22:43 +09004273 }
4274
4275 @Override
4276 public View getView(int position, View convertView, ViewGroup parent) {
4277 final View view = convertView != null ? convertView
4278 : mInflater.inflate(mTextViewResourceId, null);
4279 if (position < 0 || position >= mItemsList.size()) return view;
4280 final ImeSubtypeListItem item = mItemsList.get(position);
4281 final CharSequence imeName = item.mImeName;
4282 final CharSequence subtypeName = item.mSubtypeName;
4283 final TextView firstTextView = (TextView)view.findViewById(android.R.id.text1);
4284 final TextView secondTextView = (TextView)view.findViewById(android.R.id.text2);
4285 if (TextUtils.isEmpty(subtypeName)) {
4286 firstTextView.setText(imeName);
4287 secondTextView.setVisibility(View.GONE);
4288 } else {
4289 firstTextView.setText(subtypeName);
4290 secondTextView.setText(imeName);
4291 secondTextView.setVisibility(View.VISIBLE);
4292 }
4293 final RadioButton radioButton =
4294 (RadioButton)view.findViewById(com.android.internal.R.id.radio);
4295 radioButton.setChecked(position == mCheckedItem);
4296 return view;
4297 }
4298 }
4299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004300 void hideInputMethodMenu() {
The Android Open Source Project10592532009-03-18 17:39:46 -07004301 synchronized (mMethodMap) {
4302 hideInputMethodMenuLocked();
4303 }
4304 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004305
The Android Open Source Project10592532009-03-18 17:39:46 -07004306 void hideInputMethodMenuLocked() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08004307 if (DEBUG) Slog.v(TAG, "Hide switching menu");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004308
The Android Open Source Project10592532009-03-18 17:39:46 -07004309 if (mSwitchingDialog != null) {
4310 mSwitchingDialog.dismiss();
4311 mSwitchingDialog = null;
Yohei Yukawa1fc7a1d2018-04-18 17:31:27 -07004312 mSwitchingDialogTitleView = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004313 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004314
Yohei Yukawa849443c2019-01-21 09:02:25 -08004315 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Project10592532009-03-18 17:39:46 -07004316 mDialogBuilder = null;
The Android Open Source Project10592532009-03-18 17:39:46 -07004317 mIms = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004318 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004320 // ----------------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004321
Yohei Yukawa3d3abd22019-04-09 23:20:12 -07004322 /**
4323 * Enable or disable the given IME by updating {@link Settings.Secure#ENABLED_INPUT_METHODS}.
4324 *
4325 * @param id ID of the IME is to be manipulated. It is OK to pass IME ID that is currently not
4326 * recognized by the system.
4327 * @param enabled {@code true} if {@code id} needs to be enabled.
4328 * @return {@code true} if the IME was previously enabled. {@code false} otherwise.
4329 */
4330 private boolean setInputMethodEnabledLocked(String id, boolean enabled) {
satokd87c2592010-09-29 11:52:06 +09004331 List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
4332 .getEnabledInputMethodsAndSubtypeListLocked();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004333
satokd87c2592010-09-29 11:52:06 +09004334 if (enabled) {
4335 for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
4336 if (pair.first.equals(id)) {
4337 // We are enabling this input method, but it is already enabled.
4338 // Nothing to do. The previous state was enabled.
4339 return true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004340 }
4341 }
satokd87c2592010-09-29 11:52:06 +09004342 mSettings.appendAndPutEnabledInputMethodLocked(id, false);
4343 // Previous state was disabled.
4344 return false;
4345 } else {
4346 StringBuilder builder = new StringBuilder();
4347 if (mSettings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
4348 builder, enabledInputMethodsList, id)) {
4349 // Disabled input method is currently selected, switch to another one.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004350 final String selId = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09004351 if (id.equals(selId) && !chooseNewDefaultIMELocked()) {
4352 Slog.i(TAG, "Can't find new IME, unsetting the current input method.");
4353 resetSelectedInputMethodAndSubtypeLocked("");
satokd87c2592010-09-29 11:52:06 +09004354 }
4355 // Previous state was enabled.
4356 return true;
4357 } else {
4358 // We are disabling the input method but it is already disabled.
4359 // Nothing to do. The previous state was disabled.
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004360 return false;
4361 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004362 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004363 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08004364
satok723a27e2010-11-11 14:58:11 +09004365 private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
4366 boolean setSubtypeOnly) {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004367 mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
Tarandeep Singh89a6c482017-11-21 14:26:11 -08004368
satok723a27e2010-11-11 14:58:11 +09004369 // Set Subtype here
4370 if (imi == null || subtypeId < 0) {
4371 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
Tadashi G. Takaoka0ba75bb2010-11-09 12:19:32 -08004372 mCurrentSubtype = null;
satok723a27e2010-11-11 14:58:11 +09004373 } else {
Ken Wakasa586f0512011-01-20 22:31:01 +09004374 if (subtypeId < imi.getSubtypeCount()) {
4375 InputMethodSubtype subtype = imi.getSubtypeAt(subtypeId);
4376 mSettings.putSelectedSubtype(subtype.hashCode());
4377 mCurrentSubtype = subtype;
satok723a27e2010-11-11 14:58:11 +09004378 } else {
4379 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
satokd81e9502012-05-21 12:58:45 +09004380 // If the subtype is not specified, choose the most applicable one
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004381 mCurrentSubtype = getCurrentInputMethodSubtypeLocked();
satok723a27e2010-11-11 14:58:11 +09004382 }
satokab751aa2010-09-14 19:17:36 +09004383 }
satok723a27e2010-11-11 14:58:11 +09004384
Yohei Yukawa68645a62016-02-17 07:54:20 -08004385 if (!setSubtypeOnly) {
satok723a27e2010-11-11 14:58:11 +09004386 // Set InputMethod here
4387 mSettings.putSelectedInputMethod(imi != null ? imi.getId() : "");
4388 }
4389 }
4390
4391 private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
4392 InputMethodInfo imi = mMethodMap.get(newDefaultIme);
4393 int lastSubtypeId = NOT_A_SUBTYPE_ID;
4394 // newDefaultIme is empty when there is no candidate for the selected IME.
4395 if (imi != null && !TextUtils.isEmpty(newDefaultIme)) {
4396 String subtypeHashCode = mSettings.getLastSubtypeForInputMethodLocked(newDefaultIme);
4397 if (subtypeHashCode != null) {
4398 try {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004399 lastSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
Narayan Kamatha09b4d22016-04-15 18:32:45 +01004400 imi, Integer.parseInt(subtypeHashCode));
satok723a27e2010-11-11 14:58:11 +09004401 } catch (NumberFormatException e) {
4402 Slog.w(TAG, "HashCode for subtype looks broken: " + subtypeHashCode, e);
4403 }
4404 }
4405 }
4406 setSelectedInputMethodAndSubtypeLocked(imi, lastSubtypeId, false);
satokab751aa2010-09-14 19:17:36 +09004407 }
4408
satokab751aa2010-09-14 19:17:36 +09004409 /**
4410 * @return Return the current subtype of this input method.
4411 */
satok42c5a162011-05-26 16:46:14 +09004412 @Override
satokab751aa2010-09-14 19:17:36 +09004413 public InputMethodSubtype getCurrentInputMethodSubtype() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004414 synchronized (mMethodMap) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08004415 // TODO: Make this work even for non-current users?
Yohei Yukawa46d74762019-01-22 10:17:22 -08004416 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08004417 return null;
4418 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004419 return getCurrentInputMethodSubtypeLocked();
4420 }
4421 }
4422
4423 private InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
satokfdf419e2012-05-08 16:52:08 +09004424 if (mCurMethodId == null) {
4425 return null;
4426 }
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004427 final boolean subtypeIsSelected = mSettings.isSubtypeSelected();
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004428 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
4429 if (imi == null || imi.getSubtypeCount() == 0) {
4430 return null;
satok4e4569d2010-11-19 18:45:53 +09004431 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004432 if (!subtypeIsSelected || mCurrentSubtype == null
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004433 || !InputMethodUtils.isValidSubtypeId(imi, mCurrentSubtype.hashCode())) {
4434 int subtypeId = mSettings.getSelectedInputMethodSubtypeId(mCurMethodId);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004435 if (subtypeId == NOT_A_SUBTYPE_ID) {
4436 // If there are no selected subtypes, the framework will try to find
4437 // the most applicable subtype from explicitly or implicitly enabled
4438 // subtypes.
4439 List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004440 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004441 // If there is only one explicitly or implicitly enabled subtype,
4442 // just returns it.
4443 if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
4444 mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
4445 } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004446 mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004447 mRes, explicitlyOrImplicitlyEnabledSubtypes,
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004448 InputMethodUtils.SUBTYPE_MODE_KEYBOARD, null, true);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004449 if (mCurrentSubtype == null) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004450 mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004451 mRes, explicitlyOrImplicitlyEnabledSubtypes, null, null,
4452 true);
satok4e4569d2010-11-19 18:45:53 +09004453 }
satok3ef8b292010-11-23 06:06:29 +09004454 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004455 } else {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004456 mCurrentSubtype = InputMethodUtils.getSubtypes(imi).get(subtypeId);
satok8fbb1e82010-11-02 23:15:58 +09004457 }
4458 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004459 return mCurrentSubtype;
satokab751aa2010-09-14 19:17:36 +09004460 }
4461
Yohei Yukawaa878b952019-01-10 19:36:24 -08004462 private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
4463 synchronized (mMethodMap) {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004464 return getInputMethodListLocked(userId);
Yohei Yukawaa878b952019-01-10 19:36:24 -08004465 }
4466 }
4467
4468 private List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
4469 synchronized (mMethodMap) {
4470 return getEnabledInputMethodListLocked(userId);
4471 }
4472 }
4473
Adam Hebc67f2e2019-11-13 14:34:56 -08004474 private void onCreateInlineSuggestionsRequest(ComponentName componentName,
4475 AutofillId autofillId, IInlineSuggestionsRequestCallback callback) {
4476 synchronized (mMethodMap) {
4477 onCreateInlineSuggestionsRequestLocked(componentName, autofillId, callback);
4478 }
4479 }
4480
Yohei Yukawae24ed792018-08-28 19:10:32 -07004481 private static final class LocalServiceImpl extends InputMethodManagerInternal {
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004482 @NonNull
Yohei Yukawafffc0e52018-09-04 13:24:00 -07004483 private final InputMethodManagerService mService;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004484
Yohei Yukawafffc0e52018-09-04 13:24:00 -07004485 LocalServiceImpl(@NonNull InputMethodManagerService service) {
4486 mService = service;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004487 }
4488
4489 @Override
4490 public void setInteractive(boolean interactive) {
4491 // Do everything in handler so as not to block the caller.
Yohei Yukawaf16abb72018-09-05 11:28:42 -07004492 mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0)
4493 .sendToTarget();
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004494 }
Yohei Yukawaae61f712015-12-09 13:00:10 -08004495
4496 @Override
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07004497 public void hideCurrentInputMethod() {
Yohei Yukawaf16abb72018-09-05 11:28:42 -07004498 mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
4499 mService.mHandler.sendEmptyMessage(MSG_HIDE_CURRENT_INPUT_METHOD);
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07004500 }
Tarandeep Singh89a6c482017-11-21 14:26:11 -08004501
4502 @Override
Yohei Yukawaa878b952019-01-10 19:36:24 -08004503 public List<InputMethodInfo> getInputMethodListAsUser(int userId) {
4504 return mService.getInputMethodListAsUser(userId);
4505 }
4506
4507 @Override
4508 public List<InputMethodInfo> getEnabledInputMethodListAsUser(int userId) {
4509 return mService.getEnabledInputMethodListAsUser(userId);
4510 }
Adam Hebc67f2e2019-11-13 14:34:56 -08004511
4512 @Override
4513 public void onCreateInlineSuggestionsRequest(ComponentName componentName,
4514 AutofillId autofillId, IInlineSuggestionsRequestCallback cb) {
4515 mService.onCreateInlineSuggestionsRequest(componentName, autofillId, cb);
4516 }
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004517 }
4518
Yohei Yukawac54c1172018-09-06 11:39:50 -07004519 @BinderThread
4520 private IInputContentUriToken createInputContentUriToken(@Nullable IBinder token,
Yohei Yukawa25e08132016-06-22 16:31:41 -07004521 @Nullable Uri contentUri, @Nullable String packageName) {
Yohei Yukawa25e08132016-06-22 16:31:41 -07004522 if (token == null) {
4523 throw new NullPointerException("token");
4524 }
4525 if (packageName == null) {
4526 throw new NullPointerException("packageName");
4527 }
4528 if (contentUri == null) {
4529 throw new NullPointerException("contentUri");
4530 }
4531 final String contentUriScheme = contentUri.getScheme();
4532 if (!"content".equals(contentUriScheme)) {
4533 throw new InvalidParameterException("contentUri must have content scheme");
4534 }
4535
4536 synchronized (mMethodMap) {
4537 final int uid = Binder.getCallingUid();
4538 if (mCurMethodId == null) {
4539 return null;
4540 }
4541 if (mCurToken != token) {
4542 Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + mCurToken
4543 + " token=" + token);
4544 return null;
4545 }
4546 // We cannot simply distinguish a bad IME that reports an arbitrary package name from
4547 // an unfortunate IME whose internal state is already obsolete due to the asynchronous
4548 // nature of our system. Let's compare it with our internal record.
4549 if (!TextUtils.equals(mCurAttribute.packageName, packageName)) {
4550 Slog.e(TAG, "Ignoring createInputContentUriToken mCurAttribute.packageName="
4551 + mCurAttribute.packageName + " packageName=" + packageName);
4552 return null;
4553 }
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004554 // This user ID can never bee spoofed.
Yohei Yukawa25e08132016-06-22 16:31:41 -07004555 final int imeUserId = UserHandle.getUserId(uid);
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004556 // This user ID can never bee spoofed.
Yohei Yukawa25e08132016-06-22 16:31:41 -07004557 final int appUserId = UserHandle.getUserId(mCurClient.uid);
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004558 // This user ID may be invalid if "contentUri" embedded an invalid user ID.
4559 final int contentUriOwnerUserId = ContentProvider.getUserIdFromUri(contentUri,
4560 imeUserId);
4561 final Uri contentUriWithoutUserId = ContentProvider.getUriWithoutUserId(contentUri);
4562 // Note: InputContentUriTokenHandler.take() checks whether the IME (specified by "uid")
4563 // actually has the right to grant a read permission for "contentUriWithoutUserId" that
4564 // is claimed to belong to "contentUriOwnerUserId". For example, specifying random
4565 // content URI and/or contentUriOwnerUserId just results in a SecurityException thrown
4566 // from InputContentUriTokenHandler.take() and can never be allowed beyond what is
4567 // actually allowed to "uid", which is guaranteed to be the IME's one.
4568 return new InputContentUriTokenHandler(contentUriWithoutUserId, uid,
4569 packageName, contentUriOwnerUserId, appUserId);
Yohei Yukawa25e08132016-06-22 16:31:41 -07004570 }
4571 }
4572
Yohei Yukawac54c1172018-09-06 11:39:50 -07004573 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08004574 private void reportFullscreenMode(@NonNull IBinder token, boolean fullscreen) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004575 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08004576 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004577 return;
4578 }
4579 if (mCurClient != null && mCurClient.client != null) {
4580 mInFullscreenMode = fullscreen;
4581 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
4582 MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, mCurClient));
4583 }
4584 }
4585 }
4586
4587 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004588 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06004589 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004590
4591 IInputMethod method;
4592 ClientState client;
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004593 ClientState focusedWindowClient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004595 final Printer p = new PrintWriterPrinter(pw);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004597 synchronized (mMethodMap) {
4598 p.println("Current Input Method Manager state:");
4599 int N = mMethodList.size();
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08004600 p.println(" Input Methods: mMethodMapUpdateCount=" + mMethodMapUpdateCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004601 for (int i=0; i<N; i++) {
4602 InputMethodInfo info = mMethodList.get(i);
4603 p.println(" InputMethod #" + i + ":");
4604 info.dump(p, " ");
4605 }
4606 p.println(" Clients:");
Yohei Yukawaac9311e2018-11-20 19:25:23 -08004607 final int numClients = mClients.size();
4608 for (int i = 0; i < numClients; ++i) {
4609 final ClientState ci = mClients.valueAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004610 p.println(" Client " + ci + ":");
4611 p.println(" client=" + ci.client);
4612 p.println(" inputContext=" + ci.inputContext);
4613 p.println(" sessionRequested=" + ci.sessionRequested);
4614 p.println(" curSession=" + ci.curSession);
4615 }
The Android Open Source Project10592532009-03-18 17:39:46 -07004616 p.println(" mCurMethodId=" + mCurMethodId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004617 client = mCurClient;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07004618 p.println(" mCurClient=" + client + " mCurSeq=" + mCurSeq);
Yohei Yukawa22a89232017-02-12 16:38:59 -08004619 p.println(" mCurFocusedWindow=" + mCurFocusedWindow
4620 + " softInputMode=" +
Yohei Yukawaa468d702018-10-21 11:42:34 -07004621 InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode)
Yohei Yukawa22a89232017-02-12 16:38:59 -08004622 + " client=" + mCurFocusedWindowClient);
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004623 focusedWindowClient = mCurFocusedWindowClient;
Yohei Yukawad3ef8422018-06-07 16:28:07 -07004624 p.println(" mCurId=" + mCurId + " mHaveConnection=" + mHaveConnection
4625 + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + mVisibleBound);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004626 p.println(" mCurToken=" + mCurToken);
lumark90120a82018-08-15 00:33:03 +08004627 p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004628 p.println(" mCurIntent=" + mCurIntent);
4629 method = mCurMethod;
4630 p.println(" mCurMethod=" + mCurMethod);
4631 p.println(" mEnabledSession=" + mEnabledSession);
4632 p.println(" mShowRequested=" + mShowRequested
4633 + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
4634 + " mShowForced=" + mShowForced
4635 + " mInputShown=" + mInputShown);
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004636 p.println(" mInFullscreenMode=" + mInFullscreenMode);
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004637 p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
Yohei Yukawa81482972015-06-04 00:58:59 -07004638 p.println(" mSettingsObserver=" + mSettingsObserver);
Yohei Yukawad7248862015-06-03 23:56:12 -07004639 p.println(" mSwitchingController:");
4640 mSwitchingController.dump(p);
Yohei Yukawa68645a62016-02-17 07:54:20 -08004641 p.println(" mSettings:");
4642 mSettings.dumpLocked(p, " ");
Yohei Yukawa357b2f62017-02-14 09:40:03 -08004643
4644 p.println(" mStartInputHistory:");
4645 mStartInputHistory.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004646 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004647
Jeff Brownb88102f2010-09-08 11:49:43 -07004648 p.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004649 if (client != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004650 pw.flush();
4651 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07004652 TransferPipe.dumpAsync(client.client.asBinder(), fd, args);
4653 } catch (IOException | RemoteException e) {
4654 p.println("Failed to dump input method client: " + e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004655 }
Jeff Brownb88102f2010-09-08 11:49:43 -07004656 } else {
4657 p.println("No input method client.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004658 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004659
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004660 if (focusedWindowClient != null && client != focusedWindowClient) {
4661 p.println(" ");
4662 p.println("Warning: Current input method client doesn't match the last focused. "
4663 + "window.");
4664 p.println("Dumping input method client in the last focused window just in case.");
4665 p.println(" ");
4666 pw.flush();
4667 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07004668 TransferPipe.dumpAsync(focusedWindowClient.client.asBinder(), fd, args);
4669 } catch (IOException | RemoteException e) {
4670 p.println("Failed to dump input method client in focused window: " + e);
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004671 }
4672 }
4673
Jeff Brownb88102f2010-09-08 11:49:43 -07004674 p.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004675 if (method != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004676 pw.flush();
4677 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07004678 TransferPipe.dumpAsync(method.asBinder(), fd, args);
4679 } catch (IOException | RemoteException e) {
4680 p.println("Failed to dump input method service: " + e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004681 }
Jeff Brownb88102f2010-09-08 11:49:43 -07004682 } else {
4683 p.println("No input method service.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004684 }
4685 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004686
4687 @BinderThread
4688 @Override
4689 public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
4690 @Nullable FileDescriptor err,
4691 @NonNull String[] args, @Nullable ShellCallback callback,
4692 @NonNull ResultReceiver resultReceiver) throws RemoteException {
Yohei Yukawab8d240f2018-12-26 10:03:11 -08004693 final int callingUid = Binder.getCallingUid();
4694 // Reject any incoming calls from non-shell users, including ones from the system user.
4695 if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) {
4696 // Note that Binder#onTransact() will automatically close "in", "out", and "err" when
4697 // returned from this method, hence there is no need to close those FDs.
4698 // "resultReceiver" is the only thing that needs to be taken care of here.
4699 if (resultReceiver != null) {
4700 resultReceiver.send(ShellCommandResult.FAILURE, null);
4701 }
4702 final String errorMsg = "InputMethodManagerService does not support shell commands from"
4703 + " non-shell users. callingUid=" + callingUid
4704 + " args=" + Arrays.toString(args);
4705 if (Process.isCoreUid(callingUid)) {
4706 // Let's not crash the calling process if the caller is one of core components.
4707 Slog.e(TAG, errorMsg);
4708 return;
4709 }
4710 throw new SecurityException(errorMsg);
4711 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004712 new ShellCommandImpl(this).exec(
4713 this, in, out, err, args, callback, resultReceiver);
4714 }
4715
4716 private static final class ShellCommandImpl extends ShellCommand {
4717 @NonNull
4718 final InputMethodManagerService mService;
4719
4720 ShellCommandImpl(InputMethodManagerService service) {
4721 mService = service;
4722 }
4723
Yohei Yukawadb25df72018-12-27 08:40:41 -08004724 @RequiresPermission(allOf = {
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004725 Manifest.permission.DUMP,
4726 Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Yohei Yukawadb25df72018-12-27 08:40:41 -08004727 Manifest.permission.WRITE_SECURE_SETTINGS,
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004728 })
Yohei Yukawa926488d2017-12-11 17:24:55 -08004729 @BinderThread
4730 @ShellCommandResult
4731 @Override
4732 public int onCommand(@Nullable String cmd) {
Yohei Yukawadb25df72018-12-27 08:40:41 -08004733 // For shell command, require all the permissions here in favor of code simplicity.
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004734 Arrays.asList(
4735 Manifest.permission.DUMP,
4736 Manifest.permission.INTERACT_ACROSS_USERS_FULL,
4737 Manifest.permission.WRITE_SECURE_SETTINGS
4738 ).forEach(permission -> mService.mContext.enforceCallingPermission(permission, null));
Yohei Yukawadb25df72018-12-27 08:40:41 -08004739
4740 final long identity = Binder.clearCallingIdentity();
4741 try {
4742 return onCommandWithSystemIdentity(cmd);
4743 } finally {
4744 Binder.restoreCallingIdentity(identity);
4745 }
4746 }
4747
4748 @BinderThread
4749 @ShellCommandResult
4750 private int onCommandWithSystemIdentity(@Nullable String cmd) {
Yohei Yukawadfdab732018-02-21 07:16:30 +09004751 if ("refresh_debug_properties".equals(cmd)) {
4752 return refreshDebugProperties();
4753 }
4754
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08004755 if ("get-last-switch-user-id".equals(cmd)) {
4756 return mService.getLastSwitchUserId(this);
4757 }
4758
Yohei Yukawacac97722017-12-15 16:52:05 -08004759 // For existing "adb shell ime <command>".
4760 if ("ime".equals(cmd)) {
4761 final String imeCommand = getNextArg();
4762 if (imeCommand == null || "help".equals(imeCommand) || "-h".equals(imeCommand)) {
4763 onImeCommandHelp();
4764 return ShellCommandResult.SUCCESS;
4765 }
4766 switch (imeCommand) {
4767 case "list":
4768 return mService.handleShellCommandListInputMethods(this);
4769 case "enable":
4770 return mService.handleShellCommandEnableDisableInputMethod(this, true);
4771 case "disable":
4772 return mService.handleShellCommandEnableDisableInputMethod(this, false);
4773 case "set":
4774 return mService.handleShellCommandSetInputMethod(this);
4775 case "reset":
4776 return mService.handleShellCommandResetInputMethod(this);
4777 default:
4778 getOutPrintWriter().println("Unknown command: " + imeCommand);
4779 return ShellCommandResult.FAILURE;
4780 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004781 }
Yohei Yukawacac97722017-12-15 16:52:05 -08004782
4783 return handleDefaultCommands(cmd);
Yohei Yukawa926488d2017-12-11 17:24:55 -08004784 }
4785
4786 @BinderThread
Tarandeep Singh75a92392018-01-12 14:58:59 -08004787 @ShellCommandResult
4788 private int refreshDebugProperties() {
4789 DebugFlags.FLAG_OPTIMIZE_START_INPUT.refresh();
Tarandeep Singheadb1392018-11-09 18:15:57 +01004790 DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.refresh();
Tarandeep Singh75a92392018-01-12 14:58:59 -08004791 return ShellCommandResult.SUCCESS;
4792 }
4793
4794 @BinderThread
Yohei Yukawa926488d2017-12-11 17:24:55 -08004795 @Override
4796 public void onHelp() {
4797 try (PrintWriter pw = getOutPrintWriter()) {
4798 pw.println("InputMethodManagerService commands:");
4799 pw.println(" help");
4800 pw.println(" Prints this help text.");
4801 pw.println(" dump [options]");
4802 pw.println(" Synonym of dumpsys.");
Yohei Yukawacac97722017-12-15 16:52:05 -08004803 pw.println(" ime <command> [options]");
4804 pw.println(" Manipulate IMEs. Run \"ime help\" for details.");
4805 }
4806 }
4807
4808 private void onImeCommandHelp() {
4809 try (IndentingPrintWriter pw =
4810 new IndentingPrintWriter(getOutPrintWriter(), " ", 100)) {
4811 pw.println("ime <command>:");
4812 pw.increaseIndent();
4813
4814 pw.println("list [-a] [-s]");
4815 pw.increaseIndent();
4816 pw.println("prints all enabled input methods.");
4817 pw.increaseIndent();
4818 pw.println("-a: see all input methods");
4819 pw.println("-s: only a single summary line of each");
4820 pw.decreaseIndent();
4821 pw.decreaseIndent();
4822
Yohei Yukawae1771702019-04-10 23:20:51 -07004823 pw.println("enable [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08004824 pw.increaseIndent();
4825 pw.println("allows the given input method ID to be used.");
Yohei Yukawae1771702019-04-10 23:20:51 -07004826 pw.increaseIndent();
4827 pw.print("--user <USER_ID>: Specify which user to enable.");
4828 pw.println(" Assumes the current user if not specified.");
4829 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08004830 pw.decreaseIndent();
4831
Yohei Yukawae1771702019-04-10 23:20:51 -07004832 pw.println("disable [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08004833 pw.increaseIndent();
4834 pw.println("disallows the given input method ID to be used.");
Yohei Yukawae1771702019-04-10 23:20:51 -07004835 pw.increaseIndent();
4836 pw.print("--user <USER_ID>: Specify which user to disable.");
4837 pw.println(" Assumes the current user if not specified.");
4838 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08004839 pw.decreaseIndent();
4840
Yohei Yukawa099f80c2019-04-10 23:23:17 -07004841 pw.println("set [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08004842 pw.increaseIndent();
4843 pw.println("switches to the given input method ID.");
Yohei Yukawa099f80c2019-04-10 23:23:17 -07004844 pw.increaseIndent();
4845 pw.print("--user <USER_ID>: Specify which user to enable.");
4846 pw.println(" Assumes the current user if not specified.");
4847 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08004848 pw.decreaseIndent();
4849
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07004850 pw.println("reset [--user <USER_ID>]");
Yohei Yukawacac97722017-12-15 16:52:05 -08004851 pw.increaseIndent();
4852 pw.println("reset currently selected/enabled IMEs to the default ones as if "
4853 + "the device is initially booted with the current locale.");
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07004854 pw.increaseIndent();
4855 pw.print("--user <USER_ID>: Specify which user to reset.");
4856 pw.println(" Assumes the current user if not specified.");
4857 pw.decreaseIndent();
4858
Yohei Yukawacac97722017-12-15 16:52:05 -08004859 pw.decreaseIndent();
4860
4861 pw.decreaseIndent();
Yohei Yukawa926488d2017-12-11 17:24:55 -08004862 }
4863 }
4864 }
4865
4866 // ----------------------------------------------------------------------
4867 // Shell command handlers:
4868
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08004869 @BinderThread
4870 @ShellCommandResult
4871 private int getLastSwitchUserId(@NonNull ShellCommand shellCommand) {
4872 synchronized (mMethodMap) {
4873 shellCommand.getOutPrintWriter().println(mLastSwitchUserId);
4874 return ShellCommandResult.SUCCESS;
4875 }
4876 }
4877
Yohei Yukawa926488d2017-12-11 17:24:55 -08004878 /**
4879 * Handles {@code adb shell ime list}.
4880 * @param shellCommand {@link ShellCommand} object that is handling this command.
4881 * @return Exit code of the command.
4882 */
4883 @BinderThread
4884 @ShellCommandResult
4885 private int handleShellCommandListInputMethods(@NonNull ShellCommand shellCommand) {
4886 boolean all = false;
4887 boolean brief = false;
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004888 int userIdToBeResolved = UserHandle.USER_CURRENT;
Yohei Yukawa926488d2017-12-11 17:24:55 -08004889 while (true) {
4890 final String nextOption = shellCommand.getNextOption();
4891 if (nextOption == null) {
4892 break;
4893 }
4894 switch (nextOption) {
4895 case "-a":
4896 all = true;
4897 break;
4898 case "-s":
4899 brief = true;
4900 break;
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004901 case "-u":
4902 case "--user":
4903 userIdToBeResolved = UserHandle.parseUserArg(shellCommand.getNextArgRequired());
4904 break;
Yohei Yukawa926488d2017-12-11 17:24:55 -08004905 }
4906 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004907 synchronized (mMethodMap) {
4908 final PrintWriter pr = shellCommand.getOutPrintWriter();
4909 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
4910 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
4911 for (int userId : userIds) {
4912 final List<InputMethodInfo> methods = all
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004913 ? getInputMethodListLocked(userId)
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004914 : getEnabledInputMethodListLocked(userId);
4915 if (userIds.length > 1) {
4916 pr.print("User #");
4917 pr.print(userId);
4918 pr.println(":");
4919 }
4920 for (InputMethodInfo info : methods) {
4921 if (brief) {
4922 pr.println(info.getId());
4923 } else {
4924 pr.print(info.getId());
4925 pr.println(":");
4926 info.dump(pr::println, " ");
4927 }
4928 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004929 }
4930 }
4931 return ShellCommandResult.SUCCESS;
4932 }
4933
4934 /**
4935 * Handles {@code adb shell ime enable} and {@code adb shell ime disable}.
4936 * @param shellCommand {@link ShellCommand} object that is handling this command.
4937 * @param enabled {@code true} if the command was {@code adb shell ime enable}.
4938 * @return Exit code of the command.
4939 */
4940 @BinderThread
4941 @ShellCommandResult
Yohei Yukawa926488d2017-12-11 17:24:55 -08004942 private int handleShellCommandEnableDisableInputMethod(
4943 @NonNull ShellCommand shellCommand, boolean enabled) {
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07004944 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawae1771702019-04-10 23:20:51 -07004945 final String imeId = shellCommand.getNextArgRequired();
4946 final PrintWriter out = shellCommand.getOutPrintWriter();
4947 final PrintWriter error = shellCommand.getErrPrintWriter();
Yohei Yukawa926488d2017-12-11 17:24:55 -08004948 synchronized (mMethodMap) {
Yohei Yukawae1771702019-04-10 23:20:51 -07004949 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
4950 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
4951 for (int userId : userIds) {
4952 if (!userHasDebugPriv(userId, shellCommand)) {
4953 continue;
4954 }
4955 handleShellCommandEnableDisableInputMethodInternalLocked(userId, imeId, enabled,
4956 out, error);
Tarandeep Singh87e2e512019-03-06 14:28:52 -08004957 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004958 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004959 return ShellCommandResult.SUCCESS;
4960 }
4961
4962 /**
Yohei Yukawae1771702019-04-10 23:20:51 -07004963 * A special helper method for commands that only have {@code -u} and {@code --user} options.
4964 *
4965 * <p>You cannot use this helper method if the command has other options.</p>
4966 *
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07004967 * <p>CAVEAT: This method must be called only once before any other
4968 * {@link ShellCommand#getNextArg()} and {@link ShellCommand#getNextArgRequired()} for the
4969 * main arguments.</p>
4970 *
Yohei Yukawae1771702019-04-10 23:20:51 -07004971 * @param shellCommand {@link ShellCommand} from which options should be obtained.
4972 * @return User ID to be resolved. {@link UserHandle#CURRENT} if not specified.
4973 */
4974 @BinderThread
4975 @UserIdInt
4976 private static int handleOptionsForCommandsThatOnlyHaveUserOption(ShellCommand shellCommand) {
4977 while (true) {
4978 final String nextOption = shellCommand.getNextOption();
4979 if (nextOption == null) {
4980 break;
4981 }
4982 switch (nextOption) {
4983 case "-u":
4984 case "--user":
4985 return UserHandle.parseUserArg(shellCommand.getNextArgRequired());
4986 }
4987 }
4988 return UserHandle.USER_CURRENT;
4989 }
4990
4991 @BinderThread
4992 private void handleShellCommandEnableDisableInputMethodInternalLocked(
4993 @UserIdInt int userId, String imeId, boolean enabled, PrintWriter out,
4994 PrintWriter error) {
4995 boolean failedToEnableUnknownIme = false;
4996 boolean previouslyEnabled = false;
4997 if (userId == mSettings.getCurrentUserId()) {
4998 if (enabled && !mMethodMap.containsKey(imeId)) {
4999 failedToEnableUnknownIme = true;
5000 } else {
5001 previouslyEnabled = setInputMethodEnabledLocked(imeId, enabled);
5002 }
5003 } else {
5004 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
5005 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
5006 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
5007 new ArrayMap<>();
5008 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
5009 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
5010 methodMap, methodList);
5011 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
5012 mContext.getContentResolver(), methodMap, userId, false);
5013 if (enabled) {
5014 if (!methodMap.containsKey(imeId)) {
5015 failedToEnableUnknownIme = true;
5016 } else {
5017 for (InputMethodInfo imi : settings.getEnabledInputMethodListLocked()) {
5018 if (TextUtils.equals(imi.getId(), imeId)) {
5019 previouslyEnabled = true;
5020 break;
5021 }
5022 }
5023 if (!previouslyEnabled) {
5024 settings.appendAndPutEnabledInputMethodLocked(imeId, false);
5025 }
5026 }
5027 } else {
5028 previouslyEnabled =
5029 settings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
5030 new StringBuilder(),
5031 settings.getEnabledInputMethodsAndSubtypeListLocked(), imeId);
5032 }
5033 }
5034 if (failedToEnableUnknownIme) {
5035 error.print("Unknown input method ");
5036 error.print(imeId);
5037 error.println(" cannot be enabled for user #" + userId);
5038 } else {
5039 out.print("Input method ");
5040 out.print(imeId);
5041 out.print(": ");
5042 out.print((enabled == previouslyEnabled) ? "already " : "now ");
5043 out.print(enabled ? "enabled" : "disabled");
5044 out.print(" for user #");
5045 out.println(userId);
5046 }
5047 }
5048
5049 /**
Yohei Yukawa926488d2017-12-11 17:24:55 -08005050 * Handles {@code adb shell ime set}.
5051 * @param shellCommand {@link ShellCommand} object that is handling this command.
5052 * @return Exit code of the command.
5053 */
5054 @BinderThread
5055 @ShellCommandResult
5056 private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) {
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005057 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005058 final String imeId = shellCommand.getNextArgRequired();
5059 final PrintWriter out = shellCommand.getOutPrintWriter();
5060 final PrintWriter error = shellCommand.getErrPrintWriter();
Yohei Yukawadb25df72018-12-27 08:40:41 -08005061 synchronized (mMethodMap) {
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005062 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5063 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5064 for (int userId : userIds) {
5065 if (!userHasDebugPriv(userId, shellCommand)) {
5066 continue;
5067 }
5068 boolean failedToSelectUnknownIme = false;
5069 if (userId == mSettings.getCurrentUserId()) {
5070 if (mMethodMap.containsKey(imeId)) {
5071 setInputMethodLocked(imeId, NOT_A_SUBTYPE_ID);
5072 } else {
5073 failedToSelectUnknownIme = true;
5074 }
5075 } else {
5076 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
5077 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
5078 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
5079 new ArrayMap<>();
5080 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
5081 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
5082 methodMap, methodList);
5083 final InputMethodSettings settings = new InputMethodSettings(
5084 mContext.getResources(), mContext.getContentResolver(), methodMap,
5085 userId, false);
5086 if (methodMap.containsKey(imeId)) {
5087 settings.putSelectedInputMethod(imeId);
5088 settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
5089 } else {
5090 failedToSelectUnknownIme = true;
5091 }
5092 }
5093 if (failedToSelectUnknownIme) {
5094 error.print("Unknown input method ");
5095 error.print(imeId);
5096 error.print(" cannot be selected for user #");
5097 error.println(userId);
5098 } else {
5099 out.print("Input method ");
5100 out.print(imeId);
5101 out.print(" selected for user #");
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005102 out.println(userId);
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005103 }
Tarandeep Singh87e2e512019-03-06 14:28:52 -08005104 }
Yohei Yukawadb25df72018-12-27 08:40:41 -08005105 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005106 return ShellCommandResult.SUCCESS;
5107 }
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005108
5109 /**
5110 * Handles {@code adb shell ime reset-ime}.
5111 * @param shellCommand {@link ShellCommand} object that is handling this command.
5112 * @return Exit code of the command.
5113 */
5114 @BinderThread
5115 @ShellCommandResult
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005116 private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005117 final PrintWriter out = shellCommand.getOutPrintWriter();
5118 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005119 synchronized (mMethodMap) {
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005120 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5121 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5122 for (int userId : userIds) {
5123 if (!userHasDebugPriv(userId, shellCommand)) {
5124 continue;
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005125 }
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005126 final String nextIme;
5127 final List<InputMethodInfo> nextEnabledImes;
5128 if (userId == mSettings.getCurrentUserId()) {
5129 hideCurrentInputLocked(0, null);
5130 unbindCurrentMethodLocked();
5131 // Reset the current IME
5132 resetSelectedInputMethodAndSubtypeLocked(null);
5133 // Also reset the settings of the current IME
5134 mSettings.putSelectedInputMethod(null);
5135 // Disable all enabled IMEs.
5136 mSettings.getEnabledInputMethodListLocked().forEach(
5137 imi -> setInputMethodEnabledLocked(imi.getId(), false));
5138 // Re-enable with default enabled IMEs.
5139 InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList).forEach(
5140 imi -> setInputMethodEnabledLocked(imi.getId(), true));
5141 updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
5142 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
5143 mSettings.getEnabledInputMethodListLocked(),
5144 mSettings.getCurrentUserId(),
5145 mContext.getBasePackageName());
5146 nextIme = mSettings.getSelectedInputMethod();
5147 nextEnabledImes = mSettings.getEnabledInputMethodListLocked();
5148 } else {
5149 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
5150 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
5151 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
5152 new ArrayMap<>();
5153 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
5154 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
5155 methodMap, methodList);
5156 final InputMethodSettings settings = new InputMethodSettings(
5157 mContext.getResources(), mContext.getContentResolver(), methodMap,
5158 userId, false);
5159
5160 nextEnabledImes = InputMethodUtils.getDefaultEnabledImes(mContext, methodList);
5161 nextIme = InputMethodUtils.getMostApplicableDefaultIME(nextEnabledImes).getId();
5162
5163 // Reset enabled IMEs.
5164 settings.putEnabledInputMethodsStr("");
5165 nextEnabledImes.forEach(imi -> settings.appendAndPutEnabledInputMethodLocked(
5166 imi.getId(), false));
5167
5168 // Reset selected IME.
5169 settings.putSelectedInputMethod(nextIme);
5170 settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
5171 }
5172 out.println("Reset current and enabled IMEs for user #" + userId);
5173 out.println(" Selected: " + nextIme);
5174 nextEnabledImes.forEach(ime -> out.println(" Enabled: " + ime.getId()));
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005175 }
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005176 }
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005177 return ShellCommandResult.SUCCESS;
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005178 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07005179
Tarandeep Singh87e2e512019-03-06 14:28:52 -08005180 /**
5181 * @param userId the actual user handle obtained by {@link UserHandle#getIdentifier()}
5182 * and *not* pseudo ids like {@link UserHandle#USER_ALL etc}.
5183 * @return {@code true} if userId has debugging privileges.
5184 * i.e. {@link UserManager#DISALLOW_DEBUGGING_FEATURES} is {@code false}.
5185 */
5186 private boolean userHasDebugPriv(int userId, final ShellCommand shellCommand) {
5187 if (mUserManager.hasUserRestriction(
5188 UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(userId))) {
5189 shellCommand.getErrPrintWriter().println("User #" + userId
5190 + " is restricted with DISALLOW_DEBUGGING_FEATURES.");
5191 return false;
5192 }
5193 return true;
5194 }
5195
Yohei Yukawac54c1172018-09-06 11:39:50 -07005196 private static final class InputMethodPrivilegedOperationsImpl
5197 extends IInputMethodPrivilegedOperations.Stub {
5198 private final InputMethodManagerService mImms;
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08005199 @NonNull
Yohei Yukawac54c1172018-09-06 11:39:50 -07005200 private final IBinder mToken;
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08005201 InputMethodPrivilegedOperationsImpl(InputMethodManagerService imms,
5202 @NonNull IBinder token) {
Yohei Yukawac54c1172018-09-06 11:39:50 -07005203 mImms = imms;
5204 mToken = token;
5205 }
5206
5207 @BinderThread
5208 @Override
5209 public void setImeWindowStatus(int vis, int backDisposition) {
5210 mImms.setImeWindowStatus(mToken, vis, backDisposition);
5211 }
5212
5213 @BinderThread
5214 @Override
5215 public void reportStartInput(IBinder startInputToken) {
5216 mImms.reportStartInput(mToken, startInputToken);
5217 }
5218
5219 @BinderThread
5220 @Override
Yohei Yukawac54c1172018-09-06 11:39:50 -07005221 public IInputContentUriToken createInputContentUriToken(Uri contentUri,
5222 String packageName) {
5223 return mImms.createInputContentUriToken(mToken, contentUri, packageName);
5224 }
5225
5226 @BinderThread
5227 @Override
5228 public void reportFullscreenMode(boolean fullscreen) {
5229 mImms.reportFullscreenMode(mToken, fullscreen);
5230 }
Yohei Yukawac7ca3682018-09-09 20:48:38 -07005231
5232 @BinderThread
5233 @Override
5234 public void setInputMethod(String id) {
5235 mImms.setInputMethod(mToken, id);
5236 }
5237
5238 @BinderThread
5239 @Override
5240 public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
5241 mImms.setInputMethodAndSubtype(mToken, id, subtype);
5242 }
5243
5244 @BinderThread
5245 @Override
5246 public void hideMySoftInput(int flags) {
5247 mImms.hideMySoftInput(mToken, flags);
5248 }
5249
5250 @BinderThread
5251 @Override
5252 public void showMySoftInput(int flags) {
5253 mImms.showMySoftInput(mToken, flags);
5254 }
5255
5256 @BinderThread
5257 @Override
Yohei Yukawa41b094f2018-09-09 23:58:45 -07005258 public void updateStatusIcon(String packageName, @DrawableRes int iconId) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07005259 mImms.updateStatusIcon(mToken, packageName, iconId);
5260 }
5261
5262 @BinderThread
5263 @Override
5264 public boolean switchToPreviousInputMethod() {
5265 return mImms.switchToPreviousInputMethod(mToken);
5266 }
5267
5268 @BinderThread
5269 @Override
5270 public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
5271 return mImms.switchToNextInputMethod(mToken, onlyCurrentIme);
5272 }
5273
5274 @BinderThread
5275 @Override
5276 public boolean shouldOfferSwitchingToNextInputMethod() {
5277 return mImms.shouldOfferSwitchingToNextInputMethod(mToken);
5278 }
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07005279
5280 @BinderThread
5281 @Override
Yohei Yukawa9b60ba02019-01-21 00:06:27 -08005282 public void notifyUserAction() {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07005283 mImms.notifyUserAction(mToken);
5284 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08005285
5286 @BinderThread
5287 @Override
5288 public void reportPreRendered(EditorInfo info) {
5289 mImms.reportPreRendered(mToken, info);
5290 }
5291
5292 @BinderThread
5293 @Override
5294 public void applyImeVisibility(boolean setVisible) {
5295 mImms.applyImeVisibility(mToken, setVisible);
5296 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07005297 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005298}