Skip successive InputMethodService callbacks after orientation changed
IME is called back four methods for each input field as a IME life cycle. The four methods are onStartInput, onStartInputView, onFinishInputView and onFinishInput. After orientation changed, Those quartet methods will be called back twice. This behavior of the framework might be a bug. In order to restore the previous keyboard layout, we should skip onFinishInputView and onFinishInput of the first quartet and onStartInput and onStartInputView of the second quartet. Bug: 4311428 Change-Id: I450ddc0cce5d00abc971ffd42a507a8a86682548
This commit is contained in:
parent
dc1afa8732
commit
59f8ca752d
2 changed files with 107 additions and 70 deletions
|
@ -106,16 +106,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
|
||||||
|
|
||||||
private static final KeyboardSwitcher sInstance = new KeyboardSwitcher();
|
private static final KeyboardSwitcher sInstance = new KeyboardSwitcher();
|
||||||
|
|
||||||
public class KeyboardLayoutState {
|
private class KeyboardLayoutState {
|
||||||
private boolean mIsValid;
|
private boolean mIsValid;
|
||||||
private boolean mIsAlphabetMode;
|
private boolean mIsAlphabetMode;
|
||||||
private boolean mIsShiftLocked;
|
private boolean mIsShiftLocked;
|
||||||
private boolean mIsShifted;
|
private boolean mIsShifted;
|
||||||
|
|
||||||
public boolean isValid() {
|
|
||||||
return mIsValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
if (mCurrentId == null) {
|
if (mCurrentId == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -210,14 +206,15 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
|
||||||
mSymbolsShiftedKeyboardId = getKeyboardId(editorInfo, true, true, settingsValues);
|
mSymbolsShiftedKeyboardId = getKeyboardId(editorInfo, true, true, settingsValues);
|
||||||
mLayoutSwitchBackSymbols = mResources.getString(R.string.layout_switch_back_symbols);
|
mLayoutSwitchBackSymbols = mResources.getString(R.string.layout_switch_back_symbols);
|
||||||
setKeyboard(getKeyboard(mSavedKeyboardState.getKeyboardId()));
|
setKeyboard(getKeyboard(mSavedKeyboardState.getKeyboardId()));
|
||||||
|
mSavedKeyboardState.restore();
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.w(TAG, "loading keyboard failed: " + mMainKeyboardId, e);
|
Log.w(TAG, "loading keyboard failed: " + mMainKeyboardId, e);
|
||||||
LatinImeLogger.logOnException(mMainKeyboardId.toString(), e);
|
LatinImeLogger.logOnException(mMainKeyboardId.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyboardLayoutState getKeyboardState() {
|
public void saveKeyboardState() {
|
||||||
return mSavedKeyboardState;
|
mSavedKeyboardState.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onFinishInputView() {
|
public void onFinishInputView() {
|
||||||
|
|
|
@ -65,7 +65,6 @@ import com.android.inputmethod.keyboard.Key;
|
||||||
import com.android.inputmethod.keyboard.Keyboard;
|
import com.android.inputmethod.keyboard.Keyboard;
|
||||||
import com.android.inputmethod.keyboard.KeyboardActionListener;
|
import com.android.inputmethod.keyboard.KeyboardActionListener;
|
||||||
import com.android.inputmethod.keyboard.KeyboardSwitcher;
|
import com.android.inputmethod.keyboard.KeyboardSwitcher;
|
||||||
import com.android.inputmethod.keyboard.KeyboardSwitcher.KeyboardLayoutState;
|
|
||||||
import com.android.inputmethod.keyboard.KeyboardView;
|
import com.android.inputmethod.keyboard.KeyboardView;
|
||||||
import com.android.inputmethod.keyboard.LatinKeyboard;
|
import com.android.inputmethod.keyboard.LatinKeyboard;
|
||||||
import com.android.inputmethod.keyboard.LatinKeyboardView;
|
import com.android.inputmethod.keyboard.LatinKeyboardView;
|
||||||
|
@ -132,9 +131,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
// Key events coming any faster than this are long-presses.
|
// Key events coming any faster than this are long-presses.
|
||||||
private static final int QUICK_PRESS = 200;
|
private static final int QUICK_PRESS = 200;
|
||||||
|
|
||||||
private static final int START_INPUT_VIEW_DELAY_WHEN_SCREEN_ORIENTATION_STARTED = 10;
|
private static final int PENDING_IMS_CALLBACK_DURATION = 800;
|
||||||
private static final int ACCUMULATE_START_INPUT_VIEW_DELAY = 20;
|
|
||||||
private static final int RESTORE_KEYBOARD_STATE_DELAY = 500;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the scheme used by the Package Manager to warn of a new package installation,
|
* The name of the scheme used by the Package Manager to warn of a new package installation,
|
||||||
|
@ -239,10 +236,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
|
private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
|
||||||
private static final int MSG_SPACE_TYPED = 6;
|
private static final int MSG_SPACE_TYPED = 6;
|
||||||
private static final int MSG_SET_BIGRAM_PREDICTIONS = 7;
|
private static final int MSG_SET_BIGRAM_PREDICTIONS = 7;
|
||||||
private static final int MSG_START_ORIENTATION_CHANGE = 8;
|
private static final int MSG_PENDING_IMS_CALLBACK = 8;
|
||||||
private static final int MSG_START_INPUT_VIEW = 9;
|
|
||||||
private static final int MSG_DISPLAY_COMPLETIONS = 10;
|
|
||||||
private static final int MSG_RESTORE_KEYBOARD_LAYOUT = 11;
|
|
||||||
|
|
||||||
public UIHandler(LatinIME outerInstance) {
|
public UIHandler(LatinIME outerInstance) {
|
||||||
super(outerInstance);
|
super(outerInstance);
|
||||||
|
@ -291,16 +285,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
(LatinKeyboard)msg.obj);
|
(LatinKeyboard)msg.obj);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MSG_START_INPUT_VIEW:
|
|
||||||
latinIme.onStartInputView((EditorInfo)msg.obj, false);
|
|
||||||
break;
|
|
||||||
case MSG_DISPLAY_COMPLETIONS:
|
|
||||||
latinIme.onDisplayCompletions((CompletionInfo[])msg.obj);
|
|
||||||
break;
|
|
||||||
case MSG_RESTORE_KEYBOARD_LAYOUT:
|
|
||||||
removeMessages(MSG_UPDATE_SHIFT_STATE);
|
|
||||||
((KeyboardLayoutState)msg.obj).restore();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,47 +375,89 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
return hasMessages(MSG_SPACE_TYPED);
|
return hasMessages(MSG_SPACE_TYPED);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void postRestoreKeyboardLayout() {
|
// Working variables for the following methods.
|
||||||
final LatinIME latinIme = getOuterInstance();
|
private boolean mIsOrientationChanging;
|
||||||
final KeyboardLayoutState state = latinIme.mKeyboardSwitcher.getKeyboardState();
|
private boolean mPendingSuccesiveImsCallback;
|
||||||
if (state.isValid()) {
|
private boolean mHasPendingStartInput;
|
||||||
removeMessages(MSG_RESTORE_KEYBOARD_LAYOUT);
|
private boolean mHasPendingFinishInputView;
|
||||||
sendMessageDelayed(
|
private boolean mHasPendingFinishInput;
|
||||||
obtainMessage(MSG_RESTORE_KEYBOARD_LAYOUT, state),
|
|
||||||
RESTORE_KEYBOARD_STATE_DELAY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startOrientationChanging() {
|
public void startOrientationChanging() {
|
||||||
sendMessageDelayed(obtainMessage(MSG_START_ORIENTATION_CHANGE),
|
mIsOrientationChanging = true;
|
||||||
START_INPUT_VIEW_DELAY_WHEN_SCREEN_ORIENTATION_STARTED);
|
|
||||||
final LatinIME latinIme = getOuterInstance();
|
final LatinIME latinIme = getOuterInstance();
|
||||||
latinIme.mKeyboardSwitcher.getKeyboardState().save();
|
latinIme.mKeyboardSwitcher.saveKeyboardState();
|
||||||
postRestoreKeyboardLayout();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean postStartInputView(EditorInfo attribute) {
|
private void resetPendingImsCallback() {
|
||||||
if (hasMessages(MSG_START_ORIENTATION_CHANGE) || hasMessages(MSG_START_INPUT_VIEW)) {
|
mHasPendingFinishInputView = false;
|
||||||
removeMessages(MSG_START_INPUT_VIEW);
|
mHasPendingFinishInput = false;
|
||||||
// Postpone onStartInputView by ACCUMULATE_START_INPUT_VIEW_DELAY and see if
|
mHasPendingStartInput = false;
|
||||||
// orientation change has finished.
|
|
||||||
sendMessageDelayed(obtainMessage(MSG_START_INPUT_VIEW, attribute),
|
|
||||||
ACCUMULATE_START_INPUT_VIEW_DELAY);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean postDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
|
private void executePendingImsCallback(LatinIME latinIme, EditorInfo attribute,
|
||||||
if (hasMessages(MSG_START_INPUT_VIEW) || hasMessages(MSG_DISPLAY_COMPLETIONS)) {
|
boolean restarting) {
|
||||||
removeMessages(MSG_DISPLAY_COMPLETIONS);
|
if (mHasPendingFinishInputView)
|
||||||
// Postpone onDisplayCompletions by ACCUMULATE_START_INPUT_VIEW_DELAY.
|
latinIme.onFinishInputViewInternal(mHasPendingFinishInput);
|
||||||
sendMessageDelayed(
|
if (mHasPendingFinishInput)
|
||||||
obtainMessage(MSG_DISPLAY_COMPLETIONS, applicationSpecifiedCompletions),
|
latinIme.onFinishInputInternal();
|
||||||
ACCUMULATE_START_INPUT_VIEW_DELAY);
|
if (mHasPendingStartInput)
|
||||||
return true;
|
latinIme.onStartInputInternal(attribute, restarting);
|
||||||
|
resetPendingImsCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onStartInput(EditorInfo attribute, boolean restarting) {
|
||||||
|
if (hasMessages(MSG_PENDING_IMS_CALLBACK)) {
|
||||||
|
// Typically this is the second onStartInput after orientation changed.
|
||||||
|
mHasPendingStartInput = true;
|
||||||
|
} else {
|
||||||
|
if (mIsOrientationChanging && restarting) {
|
||||||
|
// This is the first onStartInput after orientation changed.
|
||||||
|
mIsOrientationChanging = false;
|
||||||
|
mPendingSuccesiveImsCallback = true;
|
||||||
|
}
|
||||||
|
final LatinIME latinIme = getOuterInstance();
|
||||||
|
executePendingImsCallback(latinIme, attribute, restarting);
|
||||||
|
latinIme.onStartInputInternal(attribute, restarting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onStartInputView(EditorInfo attribute, boolean restarting) {
|
||||||
|
if (hasMessages(MSG_PENDING_IMS_CALLBACK)) {
|
||||||
|
// Typically this is the second onStartInputView after orientation changed.
|
||||||
|
resetPendingImsCallback();
|
||||||
|
} else {
|
||||||
|
if (mPendingSuccesiveImsCallback) {
|
||||||
|
// This is the first onStartInputView after orientation changed.
|
||||||
|
mPendingSuccesiveImsCallback = false;
|
||||||
|
resetPendingImsCallback();
|
||||||
|
sendMessageDelayed(obtainMessage(MSG_PENDING_IMS_CALLBACK),
|
||||||
|
PENDING_IMS_CALLBACK_DURATION);
|
||||||
|
}
|
||||||
|
final LatinIME latinIme = getOuterInstance();
|
||||||
|
executePendingImsCallback(latinIme, attribute, restarting);
|
||||||
|
latinIme.onStartInputViewInternal(attribute, restarting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFinishInputView(boolean finishingInput) {
|
||||||
|
if (hasMessages(MSG_PENDING_IMS_CALLBACK)) {
|
||||||
|
// Typically this is the first onFinishInputView after orientation changed.
|
||||||
|
mHasPendingFinishInputView = true;
|
||||||
|
} else {
|
||||||
|
final LatinIME latinIme = getOuterInstance();
|
||||||
|
latinIme.onFinishInputViewInternal(finishingInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFinishInput() {
|
||||||
|
if (hasMessages(MSG_PENDING_IMS_CALLBACK)) {
|
||||||
|
// Typically this is the first onFinishInput after orientation changed.
|
||||||
|
mHasPendingFinishInput = true;
|
||||||
|
} else {
|
||||||
|
final LatinIME latinIme = getOuterInstance();
|
||||||
|
executePendingImsCallback(latinIme, null, false);
|
||||||
|
latinIme.onFinishInputInternal();
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -646,12 +672,31 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStartInputView(EditorInfo attribute, boolean restarting) {
|
public void onStartInput(EditorInfo attribute, boolean restarting) {
|
||||||
mHandler.postRestoreKeyboardLayout();
|
mHandler.onStartInput(attribute, restarting);
|
||||||
if (mHandler.postStartInputView(attribute)) {
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartInputView(EditorInfo attribute, boolean restarting) {
|
||||||
|
mHandler.onStartInputView(attribute, restarting);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFinishInputView(boolean finishingInput) {
|
||||||
|
mHandler.onFinishInputView(finishingInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFinishInput() {
|
||||||
|
mHandler.onFinishInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onStartInputInternal(EditorInfo attribute, boolean restarting) {
|
||||||
|
super.onStartInput(attribute, restarting);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onStartInputViewInternal(EditorInfo attribute, boolean restarting) {
|
||||||
|
super.onStartInputView(attribute, restarting);
|
||||||
final KeyboardSwitcher switcher = mKeyboardSwitcher;
|
final KeyboardSwitcher switcher = mKeyboardSwitcher;
|
||||||
LatinKeyboardView inputView = switcher.getKeyboardView();
|
LatinKeyboardView inputView = switcher.getKeyboardView();
|
||||||
|
|
||||||
|
@ -785,8 +830,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
if (inputView != null) inputView.closing();
|
if (inputView != null) inputView.closing();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void onFinishInputInternal() {
|
||||||
public void onFinishInput() {
|
|
||||||
super.onFinishInput();
|
super.onFinishInput();
|
||||||
|
|
||||||
LatinImeLogger.commit();
|
LatinImeLogger.commit();
|
||||||
|
@ -799,8 +843,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites();
|
if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void onFinishInputViewInternal(boolean finishingInput) {
|
||||||
public void onFinishInputView(boolean finishingInput) {
|
|
||||||
super.onFinishInputView(finishingInput);
|
super.onFinishInputView(finishingInput);
|
||||||
mKeyboardSwitcher.onFinishInputView();
|
mKeyboardSwitcher.onFinishInputView();
|
||||||
KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
|
KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
|
||||||
|
@ -939,9 +982,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
|
public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
|
||||||
if (mHandler.postDisplayCompletions(applicationSpecifiedCompletions)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.i(TAG, "Received completions:");
|
Log.i(TAG, "Received completions:");
|
||||||
if (applicationSpecifiedCompletions != null) {
|
if (applicationSpecifiedCompletions != null) {
|
||||||
|
|
Loading…
Reference in a new issue