Revert "Revert "Let IME#onFinishInput called without dup onStart..."
Revert^2 "Verify lifecycle test when screen on/off"
c2769e41ea17d7f0d261396d28ddde3563422701
Reason: Fix forward Bug 174512702 and Bug 174445559
with CL[1].
CL[1]: Icf1504d40b25fc5f53eae65d4bab48a3070db1d6
Change-Id: Id4e71a822bfde5fe6a263bbe094c0d238017efe1
This commit is contained in:
@@ -839,6 +839,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 {
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -62,9 +62,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;
|
||||
@@ -412,7 +415,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
|
||||
@@ -2352,7 +2377,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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -221,6 +221,25 @@ public final class ImeFocusController {
|
||||
mHasImeFocus = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
@@ -606,6 +606,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.
|
||||
*/
|
||||
@@ -864,12 +885,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
|
||||
@@ -1096,8 +1128,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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -52,4 +52,6 @@ oneway interface IInputMethodSession {
|
||||
void notifyImeHidden();
|
||||
|
||||
void removeImeSurface();
|
||||
|
||||
void finishInput();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -155,6 +156,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.CallbackUtils;
|
||||
import com.android.internal.inputmethod.IInputBindResultResultCallback;
|
||||
@@ -722,6 +724,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
*/
|
||||
boolean mIsInteractive = true;
|
||||
|
||||
private IPlatformCompat mPlatformCompat;
|
||||
|
||||
int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
|
||||
|
||||
/**
|
||||
@@ -1685,6 +1689,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();
|
||||
|
||||
@@ -2323,8 +2329,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;
|
||||
@@ -2472,7 +2478,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 */);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4530,15 +4537,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;
|
||||
@@ -4624,13 +4636,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());
|
||||
|
||||
@@ -1342,7 +1342,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;
|
||||
@@ -1404,7 +1404,7 @@ public final class MultiClientInputMethodManagerService {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
clientInfo.mClient.setActive(active, false /* fullscreen */);
|
||||
clientInfo.mClient.setActive(active, false /* fullscreen */, false);
|
||||
} catch (RemoteException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user