Merge "Eliminate out-of-sync IMM#mFullscreenMode error"
This commit is contained in:
@@ -387,8 +387,9 @@ public class InputMethodService extends AbstractInputMethodService {
|
||||
mInputConnection = binding.getConnection();
|
||||
if (DEBUG) Log.v(TAG, "bindInput(): binding=" + binding
|
||||
+ " ic=" + mInputConnection);
|
||||
InputConnection ic = getCurrentInputConnection();
|
||||
if (ic != null) ic.reportFullscreenMode(mIsFullscreen);
|
||||
if (mImm != null && mToken != null) {
|
||||
mImm.reportFullscreenMode(mToken, mIsFullscreen);
|
||||
}
|
||||
initialize();
|
||||
onBindInput();
|
||||
}
|
||||
@@ -1027,8 +1028,9 @@ public class InputMethodService extends AbstractInputMethodService {
|
||||
if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
|
||||
changed = true;
|
||||
mIsFullscreen = isFullscreen;
|
||||
InputConnection ic = getCurrentInputConnection();
|
||||
if (ic != null) ic.reportFullscreenMode(isFullscreen);
|
||||
if (mImm != null && mToken != null) {
|
||||
mImm.reportFullscreenMode(mToken, mIsFullscreen);
|
||||
}
|
||||
mFullscreenApplied = true;
|
||||
initialize();
|
||||
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.view.inputmethod;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.KeyCharacterMap;
|
||||
@@ -751,13 +752,19 @@ public interface InputConnection {
|
||||
public boolean clearMetaKeyStates(int states);
|
||||
|
||||
/**
|
||||
* Called by the IME to tell the client when it switches between
|
||||
* fullscreen and normal modes. This will normally be called for
|
||||
* you by the standard implementation of
|
||||
* {@link android.inputmethodservice.InputMethodService}.
|
||||
* Called back when the connected IME switches between fullscreen and normal modes.
|
||||
*
|
||||
* @return true on success, false if the input connection is no longer
|
||||
* valid.
|
||||
* <p>Note: On {@link android.os.Build.VERSION_CODES#O} and later devices, input methods are no
|
||||
* longer allowed to directly call this method at any time. To signal this event in the target
|
||||
* application, input methods should always call
|
||||
* {@link InputMethodService#updateFullscreenMode()} instead. This approach should work on API
|
||||
* {@link android.os.Build.VERSION_CODES#N_MR1} and prior devices.</p>
|
||||
*
|
||||
* @return For editor authors, the return value will always be ignored. For IME authors, this
|
||||
* always returns {@code true} on {@link android.os.Build.VERSION_CODES#N_MR1} and prior
|
||||
* devices and {@code false} on {@link android.os.Build.VERSION_CODES#O} and later
|
||||
* devices.
|
||||
* @see InputMethodManager#isFullscreenMode()
|
||||
*/
|
||||
public boolean reportFullscreenMode(boolean enabled);
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ import android.os.ResultReceiver;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.ServiceManager.ServiceNotFoundException;
|
||||
import android.os.Trace;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.SuggestionSpan;
|
||||
import android.util.Log;
|
||||
import android.util.Pools.Pool;
|
||||
@@ -396,6 +395,7 @@ public final class InputMethodManager {
|
||||
static final int MSG_TIMEOUT_INPUT_EVENT = 6;
|
||||
static final int MSG_FLUSH_INPUT_EVENT = 7;
|
||||
static final int MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER = 9;
|
||||
static final int MSG_REPORT_FULLSCREEN_MODE = 10;
|
||||
|
||||
class H extends Handler {
|
||||
H(Looper looper) {
|
||||
@@ -476,12 +476,13 @@ public final class InputMethodManager {
|
||||
}
|
||||
case MSG_SET_ACTIVE: {
|
||||
final boolean active = msg.arg1 != 0;
|
||||
final boolean fullscreen = msg.arg2 != 0;
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "handleMessage: MSG_SET_ACTIVE " + active + ", was " + mActive);
|
||||
}
|
||||
synchronized (mH) {
|
||||
mActive = active;
|
||||
mFullscreenMode = false;
|
||||
mFullscreenMode = fullscreen;
|
||||
if (!active) {
|
||||
// Some other client has starting using the IME, so note
|
||||
// that this happened and make sure our own editor's
|
||||
@@ -523,6 +524,21 @@ public final class InputMethodManager {
|
||||
synchronized (mH) {
|
||||
mNextUserActionNotificationSequenceNumber = msg.arg1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case MSG_REPORT_FULLSCREEN_MODE: {
|
||||
final boolean fullscreen = msg.arg1 != 0;
|
||||
InputConnection ic = null;
|
||||
synchronized (mH) {
|
||||
mFullscreenMode = fullscreen;
|
||||
if (mServedInputConnectionWrapper != null) {
|
||||
ic = mServedInputConnectionWrapper.getInputConnection();
|
||||
}
|
||||
}
|
||||
if (ic != null) {
|
||||
ic.reportFullscreenMode(fullscreen);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -556,19 +572,12 @@ public final class InputMethodManager {
|
||||
mParentInputMethodManager.notifyUserAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReportFullscreenMode(boolean enabled, boolean calledInBackground) {
|
||||
mParentInputMethodManager.onReportFullscreenMode(enabled, calledInBackground,
|
||||
getInputMethodId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ControlledInputConnectionWrapper{"
|
||||
+ "connection=" + getInputConnection()
|
||||
+ " finished=" + isFinished()
|
||||
+ " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
|
||||
+ " mInputMethodId=" + getInputMethodId()
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -600,24 +609,31 @@ public final class InputMethodManager {
|
||||
|
||||
@Override
|
||||
public void onBindMethod(InputBindResult res) {
|
||||
mH.sendMessage(mH.obtainMessage(MSG_BIND, res));
|
||||
mH.obtainMessage(MSG_BIND, res).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnbindMethod(int sequence, @InputMethodClient.UnbindReason int unbindReason) {
|
||||
mH.sendMessage(mH.obtainMessage(MSG_UNBIND, sequence, unbindReason));
|
||||
mH.obtainMessage(MSG_UNBIND, sequence, unbindReason).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActive(boolean active) {
|
||||
mH.sendMessage(mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, 0));
|
||||
public void setActive(boolean active, boolean fullscreen) {
|
||||
mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, fullscreen ? 1 : 0).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserActionNotificationSequenceNumber(int sequenceNumber) {
|
||||
mH.sendMessage(mH.obtainMessage(MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER,
|
||||
sequenceNumber, 0));
|
||||
mH.obtainMessage(MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER, sequenceNumber, 0)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportFullscreenMode(boolean fullscreen) {
|
||||
mH.obtainMessage(MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, 0)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
|
||||
@@ -730,16 +746,6 @@ public final class InputMethodManager {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void onReportFullscreenMode(boolean fullScreen, boolean calledInBackground,
|
||||
String inputMethodId) {
|
||||
synchronized (mH) {
|
||||
if (!calledInBackground || TextUtils.equals(mCurId, inputMethodId)) {
|
||||
mFullscreenMode = fullScreen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) {
|
||||
try {
|
||||
@@ -769,6 +775,17 @@ public final class InputMethodManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void reportFullscreenMode(IBinder token, boolean fullscreen) {
|
||||
try {
|
||||
mService.reportFullscreenMode(token, fullscreen);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given view is the currently active view for the
|
||||
* input method.
|
||||
@@ -1274,9 +1291,6 @@ public final class InputMethodManager {
|
||||
mCurId = res.id;
|
||||
mNextUserActionNotificationSequenceNumber =
|
||||
res.userActionNotificationSequenceNumber;
|
||||
if (mServedInputConnectionWrapper != null) {
|
||||
mServedInputConnectionWrapper.setInputMethodId(mCurId);
|
||||
}
|
||||
} else {
|
||||
if (res.channel != null && res.channel != mCurChannel) {
|
||||
res.channel.dispose();
|
||||
@@ -2341,6 +2355,7 @@ public final class InputMethodManager {
|
||||
+ " mHasBeenInactive=" + mHasBeenInactive
|
||||
+ " mBindSequence=" + mBindSequence
|
||||
+ " mCurId=" + mCurId);
|
||||
p.println(" mFullscreenMode=" + mFullscreenMode);
|
||||
p.println(" mCurMethod=" + mCurMethod);
|
||||
p.println(" mCurRootView=" + mCurRootView);
|
||||
p.println(" mServedView=" + mServedView);
|
||||
|
||||
@@ -57,7 +57,6 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
private static final int DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS = 81;
|
||||
private static final int DO_BEGIN_BATCH_EDIT = 90;
|
||||
private static final int DO_END_BATCH_EDIT = 95;
|
||||
private static final int DO_REPORT_FULLSCREEN_MODE = 100;
|
||||
private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
|
||||
private static final int DO_CLEAR_META_KEY_STATES = 130;
|
||||
private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
|
||||
@@ -73,8 +72,6 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
private Object mLock = new Object();
|
||||
@GuardedBy("mLock")
|
||||
private boolean mFinished = false;
|
||||
@GuardedBy("mLock")
|
||||
private String mInputMethodId;
|
||||
|
||||
static class SomeArgs {
|
||||
Object arg1;
|
||||
@@ -113,18 +110,6 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
public String getInputMethodId() {
|
||||
synchronized (mLock) {
|
||||
return mInputMethodId;
|
||||
}
|
||||
}
|
||||
|
||||
public void setInputMethodId(final String inputMethodId) {
|
||||
synchronized (mLock) {
|
||||
mInputMethodId = inputMethodId;
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected boolean isActive();
|
||||
|
||||
/**
|
||||
@@ -133,14 +118,6 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
*/
|
||||
abstract protected void onUserAction();
|
||||
|
||||
/**
|
||||
* Called when the input method started or stopped full-screen mode.
|
||||
* @param enabled {@code true} if the input method starts full-screen mode.
|
||||
* @param calledInBackground {@code true} if this input connection is in a state when incoming
|
||||
* events are usually ignored.
|
||||
*/
|
||||
abstract protected void onReportFullscreenMode(boolean enabled, boolean calledInBackground);
|
||||
|
||||
public void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback) {
|
||||
dispatchMessage(obtainMessageIISC(DO_GET_TEXT_AFTER_CURSOR, length, flags, seq, callback));
|
||||
}
|
||||
@@ -225,10 +202,6 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
|
||||
}
|
||||
|
||||
public void reportFullscreenMode(boolean enabled) {
|
||||
dispatchMessage(obtainMessageII(DO_REPORT_FULLSCREEN_MODE, enabled ? 1 : 0, 0));
|
||||
}
|
||||
|
||||
public void performPrivateCommand(String action, Bundle data) {
|
||||
dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
|
||||
}
|
||||
@@ -486,23 +459,6 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
ic.endBatchEdit();
|
||||
return;
|
||||
}
|
||||
case DO_REPORT_FULLSCREEN_MODE: {
|
||||
InputConnection ic = getInputConnection();
|
||||
boolean isBackground = false;
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "reportFullscreenMode on inexistent InputConnection");
|
||||
isBackground = true;
|
||||
}
|
||||
final boolean enabled = msg.arg1 == 1;
|
||||
if (!isBackground) {
|
||||
ic.reportFullscreenMode(enabled);
|
||||
}
|
||||
// Due to the nature of asynchronous event handling, currently InputMethodService
|
||||
// has relied on the fact that #reportFullscreenMode() can be handled even when the
|
||||
// InputConnection is inactive. We have to notify this event to InputMethodManager.
|
||||
onReportFullscreenMode(enabled, isBackground);
|
||||
return;
|
||||
}
|
||||
case DO_PERFORM_PRIVATE_COMMAND: {
|
||||
InputConnection ic = getInputConnection();
|
||||
if (ic == null || !isActive()) {
|
||||
|
||||
@@ -62,9 +62,7 @@ import com.android.internal.view.IInputContextCallback;
|
||||
void beginBatchEdit();
|
||||
|
||||
void endBatchEdit();
|
||||
|
||||
void reportFullscreenMode(boolean enabled);
|
||||
|
||||
|
||||
void sendKeyEvent(in KeyEvent event);
|
||||
|
||||
void clearMetaKeyStates(int states);
|
||||
|
||||
@@ -27,6 +27,7 @@ oneway interface IInputMethodClient {
|
||||
void onBindMethod(in InputBindResult res);
|
||||
// unbindReason corresponds to InputMethodClient.UnbindReason.
|
||||
void onUnbindMethod(int sequence, int unbindReason);
|
||||
void setActive(boolean active);
|
||||
void setActive(boolean active, boolean fullscreen);
|
||||
void setUserActionNotificationSequenceNumber(int sequenceNumber);
|
||||
void reportFullscreenMode(boolean fullscreen);
|
||||
}
|
||||
|
||||
@@ -86,5 +86,7 @@ interface IInputMethodManager {
|
||||
IInputContentUriToken createInputContentUriToken(in IBinder token, in Uri contentUri,
|
||||
in String packageName);
|
||||
|
||||
void reportFullscreenMode(in IBinder token, boolean fullscreen);
|
||||
|
||||
oneway void notifyUserAction(int sequenceNumber);
|
||||
}
|
||||
|
||||
@@ -467,12 +467,8 @@ public class InputConnectionWrapper implements InputConnection {
|
||||
}
|
||||
|
||||
public boolean reportFullscreenMode(boolean enabled) {
|
||||
try {
|
||||
mIInputContext.reportFullscreenMode(enabled);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
}
|
||||
// Nothing should happen when called from input method.
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean performPrivateCommand(String action, Bundle data) {
|
||||
|
||||
@@ -181,6 +181,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
static final int MSG_SET_ACTIVE = 3020;
|
||||
static final int MSG_SET_INTERACTIVE = 3030;
|
||||
static final int MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER = 3040;
|
||||
static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
|
||||
static final int MSG_SWITCH_IME = 3050;
|
||||
|
||||
static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
|
||||
@@ -410,6 +411,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
*/
|
||||
boolean mInputShown;
|
||||
|
||||
/**
|
||||
* {@code true} if the current input method is in fullscreen mode.
|
||||
*/
|
||||
boolean mInFullscreenMode;
|
||||
|
||||
/**
|
||||
* The Intent used to connect to the current input method.
|
||||
*/
|
||||
@@ -1265,8 +1271,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
|
||||
MSG_SET_ACTIVE, 0, mCurClient));
|
||||
executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
|
||||
MSG_SET_ACTIVE, 0, 0, mCurClient));
|
||||
executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
|
||||
MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client));
|
||||
mCurClient.sessionRequested = false;
|
||||
@@ -1649,6 +1655,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
if (mStatusBar != null) {
|
||||
mStatusBar.setIconVisibility(mSlotIme, false);
|
||||
}
|
||||
mInFullscreenMode = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2915,7 +2922,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
}
|
||||
case MSG_SET_ACTIVE:
|
||||
try {
|
||||
((ClientState)msg.obj).client.setActive(msg.arg1 != 0);
|
||||
((ClientState)msg.obj).client.setActive(msg.arg1 != 0, msg.arg2 != 0);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
|
||||
+ ((ClientState)msg.obj).pid + " uid "
|
||||
@@ -2942,6 +2949,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case MSG_REPORT_FULLSCREEN_MODE: {
|
||||
final boolean fullscreen = msg.arg1 != 0;
|
||||
final ClientState clientState = (ClientState)msg.obj;
|
||||
try {
|
||||
clientState.client.reportFullscreenMode(fullscreen);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Got RemoteException sending "
|
||||
+ "reportFullscreen(" + fullscreen + ") notification to pid="
|
||||
+ clientState.pid + " uid=" + clientState.uid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------
|
||||
case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
|
||||
@@ -2962,8 +2981,9 @@ 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.obtainMessageIO(
|
||||
MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mCurClient));
|
||||
executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
|
||||
MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mInFullscreenMode ? 1 : 0,
|
||||
mCurClient));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3962,6 +3982,23 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportFullscreenMode(IBinder token, boolean fullscreen) {
|
||||
if (!calledFromValidUser()) {
|
||||
return;
|
||||
}
|
||||
synchronized (mMethodMap) {
|
||||
if (!calledWithValidToken(token)) {
|
||||
return;
|
||||
}
|
||||
if (mCurClient != null && mCurClient.client != null) {
|
||||
mInFullscreenMode = fullscreen;
|
||||
executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
|
||||
MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, mCurClient));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
|
||||
@@ -4014,6 +4051,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
+ " mShowExplicitlyRequested=" + mShowExplicitlyRequested
|
||||
+ " mShowForced=" + mShowForced
|
||||
+ " mInputShown=" + mInputShown);
|
||||
p.println(" mInFullscreenMode=" + mInFullscreenMode);
|
||||
p.println(" mCurUserActionNotificationSequenceNumber="
|
||||
+ mCurUserActionNotificationSequenceNumber);
|
||||
p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
|
||||
|
||||
@@ -248,4 +248,9 @@ public class BridgeIInputMethodManager implements IInputMethodManager {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportFullscreenMode(IBinder token, boolean fullscreen) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user