summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/test-current.txt8
-rw-r--r--core/java/android/inputmethodservice/IInputMethodSessionWrapper.java10
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java29
-rw-r--r--core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java9
-rw-r--r--core/java/android/view/ImeFocusController.java20
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java37
-rw-r--r--core/java/com/android/internal/view/IInputMethodClient.aidl2
-rw-r--r--core/java/com/android/internal/view/IInputMethodSession.aidl2
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java43
-rw-r--r--services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java4
10 files changed, 146 insertions, 18 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 52a79bae6324..52d61420b631 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -832,6 +832,14 @@ package android.hardware.soundtrigger {
}
+package android.inputmethodservice {
+
+ public class InputMethodService extends android.inputmethodservice.AbstractInputMethodService {
+ field public static final long FINISH_INPUT_NO_FALLBACK_CONNECTION = 156215187L; // 0x94fa793L
+ }
+
+}
+
package android.location {
public final class GnssClock implements android.os.Parcelable {
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index e9de27456f97..0766917642e8 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -54,6 +54,8 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
private static final int DO_VIEW_CLICKED = 115;
private static final int DO_NOTIFY_IME_HIDDEN = 120;
private static final int DO_REMOVE_IME_SURFACE = 130;
+ private static final int DO_FINISH_INPUT = 140;
+
@UnsupportedAppUsage
HandlerCaller mCaller;
@@ -141,6 +143,10 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
mInputMethodSession.removeImeSurface();
return;
}
+ case DO_FINISH_INPUT: {
+ mInputMethodSession.finishInput();
+ return;
+ }
}
Log.w(TAG, "Unhandled message code: " + msg.what);
}
@@ -222,6 +228,10 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_SESSION));
}
+ @Override
+ public void finishInput() {
+ mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_INPUT));
+ }
private final class ImeInputEventReceiver extends InputEventReceiver
implements InputMethodSession.EventCallback {
private final SparseArray<InputEvent> mPendingEvents = new SparseArray<InputEvent>();
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index ae260e16806f..4a5d831cd705 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -61,9 +61,12 @@ import android.annotation.IntDef;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.annotation.UiContext;
import android.app.ActivityManager;
import android.app.Dialog;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -411,7 +414,29 @@ public class InputMethodService extends AbstractInputMethodService {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
int mTheme = 0;
-
+
+ /**
+ * Finish the {@link InputConnection} when the device becomes
+ * {@link android.os.PowerManager#isInteractive non-interactive}.
+ *
+ * <p>
+ * If enabled by the current {@link InputMethodService input method}, the current input
+ * connection will be {@link InputMethodService#onFinishInput finished} whenever the devices
+ * becomes non-interactive.
+ *
+ * <p>
+ * If not enabled, the current input connection will instead be silently deactivated when the
+ * devices becomes non-interactive, and an {@link InputMethodService#onFinishInput
+ * onFinishInput()} {@link InputMethodService#onStartInput onStartInput()} pair is dispatched
+ * when the device becomes interactive again.
+ *
+ * @hide
+ */
+ @TestApi
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ public static final long FINISH_INPUT_NO_FALLBACK_CONNECTION = 156215187L; // This is a bug id.
+
LayoutInflater mInflater;
TypedArray mThemeAttrs;
@UnsupportedAppUsage
@@ -2325,7 +2350,7 @@ public class InputMethodService extends AbstractInputMethodService {
}
void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
- if (!restarting) {
+ if (!restarting && mInputStarted) {
doFinishInput();
}
ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", this);
diff --git a/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java b/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
index dbb669be1402..2db9ed1103fa 100644
--- a/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
+++ b/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
@@ -23,6 +23,7 @@ import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.Looper;
+import android.os.RemoteException;
import android.os.ResultReceiver;
import android.util.Log;
import android.view.InputChannel;
@@ -38,8 +39,8 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.inputmethod.IMultiClientInputMethodSession;
import com.android.internal.inputmethod.CancellationGroup;
+import com.android.internal.inputmethod.IMultiClientInputMethodSession;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.view.IInputContext;
@@ -303,6 +304,12 @@ final class MultiClientInputMethodClientCallbackAdaptor {
// no-op for multi-session
reportNotSupported();
}
+
+ @Override
+ public void finishInput() throws RemoteException {
+ // no-op for multi-session
+ reportNotSupported();
+ }
}
private static final class MultiClientInputMethodSessionImpl
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index efc0bd2785f4..4a5c95f43d46 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -222,6 +222,25 @@ public final class ImeFocusController {
}
/**
+ * To handle the lifecycle of the input connection when the device interactivity state changed.
+ * (i.e. Calling IMS#onFinishInput when the device screen-off and Calling IMS#onStartInput
+ * when the device screen-on again).
+ */
+ @UiThread
+ public void onInteractiveChanged(boolean interactive) {
+ final InputMethodManagerDelegate immDelegate = getImmDelegate();
+ if (!immDelegate.isCurrentRootView(mViewRootImpl)) {
+ return;
+ }
+ if (interactive) {
+ final View focusedView = mViewRootImpl.mView.findFocus();
+ onViewFocusChanged(focusedView, focusedView != null);
+ } else {
+ mDelegate.finishInputAndReportToIme();
+ }
+ }
+
+ /**
* @param windowAttribute {@link WindowManager.LayoutParams} to be checked.
* @return Whether the window is in local focus mode or not.
*/
@@ -256,6 +275,7 @@ public final class ImeFocusController {
@WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags,
boolean forceNewFocus);
void finishInput();
+ void finishInputAndReportToIme();
void closeCurrentIme();
void finishComposingText();
void setCurrentRootView(ViewRootImpl rootView);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 3c89a4bfad59..315d4461692c 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -599,6 +599,27 @@ public final class InputMethodManager {
}
/**
+ * Used by {@link ImeFocusController} to finish input connection and callback
+ * {@link InputMethodService#onFinishInput()}.
+ *
+ * This method is especially for when ImeFocusController received device screen-off event to
+ * ensure the entire finish input connection and the connection lifecycle callback to
+ * IME can be done for security concern.
+ */
+ @Override
+ public void finishInputAndReportToIme() {
+ synchronized (mH) {
+ finishInputLocked();
+ if (mCurMethod != null) {
+ try {
+ mCurMethod.finishInput();
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+
+ /**
* Used by {@link ImeFocusController} to hide current input method editor.
*/
@Override
@@ -849,12 +870,23 @@ public final class InputMethodManager {
case MSG_SET_ACTIVE: {
final boolean active = msg.arg1 != 0;
final boolean fullscreen = msg.arg2 != 0;
+ final boolean reportToImeController = msg.obj != null && (boolean) msg.obj;
if (DEBUG) {
Log.i(TAG, "handleMessage: MSG_SET_ACTIVE " + active + ", was " + mActive);
}
synchronized (mH) {
mActive = active;
mFullscreenMode = fullscreen;
+
+ // Report active state to ImeFocusController to handle IME input
+ // connection lifecycle callback when it allowed.
+ final ImeFocusController controller = getFocusController();
+ final View rootView = mCurRootView != null ? mCurRootView.getView() : null;
+ if (controller != null && rootView != null && reportToImeController) {
+ rootView.post(() -> controller.onInteractiveChanged(active));
+ return;
+ }
+
if (!active) {
// Some other client has starting using the IME, so note
// that this happened and make sure our own editor's
@@ -1061,8 +1093,9 @@ public final class InputMethodManager {
}
@Override
- public void setActive(boolean active, boolean fullscreen) {
- mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, fullscreen ? 1 : 0).sendToTarget();
+ public void setActive(boolean active, boolean fullscreen, boolean reportToImeController) {
+ mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, fullscreen ? 1 : 0,
+ reportToImeController).sendToTarget();
}
@Override
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index 1145f5183206..ec9a0a2f4801 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -25,7 +25,7 @@ import com.android.internal.view.InputBindResult;
oneway interface IInputMethodClient {
void onBindMethod(in InputBindResult res);
void onUnbindMethod(int sequence, int unbindReason);
- void setActive(boolean active, boolean fullscreen);
+ void setActive(boolean active, boolean fullscreen, boolean reportToImeController);
void scheduleStartInputIfNecessary(boolean fullscreen);
void reportFullscreenMode(boolean fullscreen);
void applyImeVisibility(boolean setVisible);
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
index 0319e3637384..c6afd78ec04b 100644
--- a/core/java/com/android/internal/view/IInputMethodSession.aidl
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -52,4 +52,6 @@ oneway interface IInputMethodSession {
void notifyImeHidden();
void removeImeSurface();
+
+ void finishInput();
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index cfb5116c47f3..4331198daacf 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -15,6 +15,7 @@
package com.android.server.inputmethod;
+import static android.inputmethodservice.InputMethodService.FINISH_INPUT_NO_FALLBACK_CONNECTION;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PROTO;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
@@ -152,6 +153,7 @@ import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.compat.IPlatformCompat;
import com.android.internal.content.PackageMonitor;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
@@ -709,6 +711,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
*/
boolean mIsInteractive = true;
+ private IPlatformCompat mPlatformCompat;
+
int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
/**
@@ -1670,6 +1674,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
mHasFeature = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_INPUT_METHODS);
+ mPlatformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
mIsLowRam = ActivityManager.isLowRamDeviceStatic();
@@ -2306,8 +2312,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
- MSG_SET_ACTIVE, 0, 0, mCurClient));
+ scheduleSetActiveToClient(mCurClient, false /* active */, false /* fullscreen */,
+ false /* reportToImeController */);
executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client));
mCurClient.sessionRequested = false;
@@ -2449,7 +2455,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// If the screen is on, inform the new client it is active
if (mIsInteractive) {
- executeOrSendMessage(cs.client, mCaller.obtainMessageIO(MSG_SET_ACTIVE, 1, cs));
+ scheduleSetActiveToClient(cs, true /* active */, false /* fullscreen */,
+ false /* reportToImeController */);
}
}
@@ -4452,15 +4459,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
args.recycle();
return true;
}
- case MSG_SET_ACTIVE:
+ case MSG_SET_ACTIVE: {
+ args = (SomeArgs) msg.obj;
+ final ClientState clientState = (ClientState) args.arg1;
try {
- ((ClientState)msg.obj).client.setActive(msg.arg1 != 0, msg.arg2 != 0);
+ clientState.client.setActive(args.argi1 != 0 /* active */,
+ args.argi2 != 0 /* fullScreen */,
+ args.argi3 != 0 /* reportToImeController */);
} catch (RemoteException e) {
Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
- + ((ClientState)msg.obj).pid + " uid "
- + ((ClientState)msg.obj).uid);
+ + clientState.pid + " uid " + clientState.uid);
}
+ args.recycle();
return true;
+ }
case MSG_SET_INTERACTIVE:
handleSetInteractive(msg.arg1 != 0);
return true;
@@ -4546,13 +4558,24 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// Inform the current client of the change in active status
if (mCurClient != null && mCurClient.client != null) {
- executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
- MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mInFullscreenMode ? 1 : 0,
- mCurClient));
+ boolean reportToImeController = false;
+ try {
+ reportToImeController = mPlatformCompat.isChangeEnabledByUid(
+ FINISH_INPUT_NO_FALLBACK_CONNECTION, mCurMethodUid);
+ } catch (RemoteException e) {
+ }
+ scheduleSetActiveToClient(mCurClient, mIsInteractive, mInFullscreenMode,
+ reportToImeController);
}
}
}
+ private void scheduleSetActiveToClient(ClientState state, boolean active, boolean fullscreen,
+ boolean reportToImeController) {
+ executeOrSendMessage(state.client, mCaller.obtainMessageIIIIO(MSG_SET_ACTIVE,
+ active ? 1 : 0, fullscreen ? 1 : 0, reportToImeController ? 1 : 0, 0, state));
+ }
+
private boolean chooseNewDefaultIMELocked() {
final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
mSettings.getEnabledInputMethodListLocked());
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 7af27ca46f68..a3fb13593209 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1338,7 +1338,7 @@ public final class MultiClientInputMethodManagerService {
switch (clientInfo.mState) {
case InputMethodClientState.WAITING_FOR_IME_SESSION:
try {
- clientInfo.mClient.setActive(true, false);
+ clientInfo.mClient.setActive(true, false, false);
} catch (RemoteException e) {
// TODO(yukawa): Remove this client.
return;
@@ -1400,7 +1400,7 @@ public final class MultiClientInputMethodManagerService {
return;
}
try {
- clientInfo.mClient.setActive(active, false /* fullscreen */);
+ clientInfo.mClient.setActive(active, false /* fullscreen */, false);
} catch (RemoteException e) {
return;
}