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:
Tadashi G. Takaoka 2011-09-29 17:27:48 +09:00
parent dc1afa8732
commit 59f8ca752d
2 changed files with 107 additions and 70 deletions

View file

@ -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() {

View file

@ -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) {