Merge remote-tracking branch 'goog/master' into merge
This commit is contained in:
commit
95f2fb6b92
10 changed files with 333 additions and 259 deletions
|
@ -35,29 +35,26 @@
|
|||
latin:keyEdgeFlags="left" />
|
||||
<include
|
||||
latin:keyboardLayout="@xml/kbd_qwerty_f1" />
|
||||
<Key
|
||||
latin:keyStyle="spaceKeyStyle"
|
||||
latin:keyWidth="40%p" />
|
||||
<switch>
|
||||
<case
|
||||
latin:mode="web"
|
||||
>
|
||||
<Key
|
||||
latin:keyStyle="spaceKeyStyle"
|
||||
latin:keyWidth="20%p" />
|
||||
<Key
|
||||
<Key
|
||||
latin:keyStyle="tabKeyStyle"
|
||||
latin:keyWidth="20%p" />
|
||||
latin:keyWidth="10%p" />
|
||||
</case>
|
||||
<default>
|
||||
<Key
|
||||
latin:keyStyle="spaceKeyStyle"
|
||||
latin:keyWidth="40%p" />
|
||||
latin:keyLabel="."
|
||||
latin:keyHintIcon="@drawable/hint_popup"
|
||||
latin:popupCharacters="@string/alternates_for_punctuation"
|
||||
latin:maxPopupKeyboardColumn="7"
|
||||
latin:keyStyle="functionalKeyStyle" />
|
||||
</default>
|
||||
</switch>
|
||||
<Key
|
||||
latin:keyLabel="."
|
||||
latin:keyHintIcon="@drawable/hint_popup"
|
||||
latin:popupCharacters="@string/alternates_for_punctuation"
|
||||
latin:maxPopupKeyboardColumn="7"
|
||||
latin:keyStyle="functionalKeyStyle" />
|
||||
<switch>
|
||||
<case
|
||||
latin:mode="im"
|
||||
|
|
|
@ -153,7 +153,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
|
|||
|
||||
makeSymbolsKeyboardIds(id.mMode, attribute);
|
||||
mCurrentId = id;
|
||||
mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
|
||||
mInputView.setKeyPreviewEnabled(mInputMethodService.getPopupOn());
|
||||
setKeyboard(getKeyboard(id));
|
||||
}
|
||||
|
||||
|
|
|
@ -106,26 +106,24 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
// Main keyboard
|
||||
private Keyboard mKeyboard;
|
||||
|
||||
// Key preview popup
|
||||
// Key preview
|
||||
private boolean mInForeground;
|
||||
private TextView mPreviewText;
|
||||
private int mPreviewTextSizeLarge;
|
||||
private final int[] mOffsetInWindow = new int[2];
|
||||
private int mOldPreviewKeyIndex = KeyDetector.NOT_A_KEY;
|
||||
private boolean mShowPreview = true;
|
||||
private int mPopupPreviewOffsetX;
|
||||
private int mPopupPreviewOffsetY;
|
||||
private int mPopupPreviewDisplayedY;
|
||||
private boolean mShowKeyPreview = true;
|
||||
private int mKeyPreviewDisplayedY;
|
||||
private final int mDelayBeforePreview;
|
||||
private final int mDelayAfterPreview;
|
||||
private ViewGroup mPreviewPlacer;
|
||||
|
||||
// Popup mini keyboard
|
||||
private PopupWindow mMiniKeyboardPopup;
|
||||
// Mini keyboard
|
||||
private PopupWindow mMiniKeyboardWindow;
|
||||
private KeyboardView mMiniKeyboardView;
|
||||
private final WeakHashMap<Key, View> mMiniKeyboardCache = new WeakHashMap<Key, View>();
|
||||
private int mMiniKeyboardOriginX;
|
||||
private int mMiniKeyboardOriginY;
|
||||
private long mMiniKeyboardPopupTime;
|
||||
private long mMiniKeyboardDisplayedTime;
|
||||
private int[] mWindowOffset;
|
||||
private final float mMiniKeyboardSlideAllowance;
|
||||
private int mMiniKeyboardTrackerId;
|
||||
|
@ -185,8 +183,8 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
private final UIHandler mHandler = new UIHandler();
|
||||
|
||||
class UIHandler extends Handler {
|
||||
private static final int MSG_POPUP_PREVIEW = 1;
|
||||
private static final int MSG_DISMISS_PREVIEW = 2;
|
||||
private static final int MSG_SHOW_KEY_PREVIEW = 1;
|
||||
private static final int MSG_DISMISS_KEY_PREVIEW = 2;
|
||||
private static final int MSG_REPEAT_KEY = 3;
|
||||
private static final int MSG_LONGPRESS_KEY = 4;
|
||||
private static final int MSG_LONGPRESS_SHIFT_KEY = 5;
|
||||
|
@ -196,10 +194,10 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_POPUP_PREVIEW:
|
||||
case MSG_SHOW_KEY_PREVIEW:
|
||||
showKey(msg.arg1, (PointerTracker)msg.obj);
|
||||
break;
|
||||
case MSG_DISMISS_PREVIEW:
|
||||
case MSG_DISMISS_KEY_PREVIEW:
|
||||
mPreviewText.setVisibility(View.INVISIBLE);
|
||||
break;
|
||||
case MSG_REPEAT_KEY: {
|
||||
|
@ -210,7 +208,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
}
|
||||
case MSG_LONGPRESS_KEY: {
|
||||
final PointerTracker tracker = (PointerTracker)msg.obj;
|
||||
openPopupIfRequired(msg.arg1, tracker);
|
||||
openMiniKeyboardIfRequired(msg.arg1, tracker);
|
||||
break;
|
||||
}
|
||||
case MSG_LONGPRESS_SHIFT_KEY: {
|
||||
|
@ -221,26 +219,35 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
}
|
||||
}
|
||||
|
||||
public void popupPreview(long delay, int keyIndex, PointerTracker tracker) {
|
||||
removeMessages(MSG_POPUP_PREVIEW);
|
||||
public void showKeyPreview(long delay, int keyIndex, PointerTracker tracker) {
|
||||
removeMessages(MSG_SHOW_KEY_PREVIEW);
|
||||
if (mPreviewText.getVisibility() == VISIBLE || delay == 0) {
|
||||
// Show right away, if it's already visible and finger is moving around
|
||||
showKey(keyIndex, tracker);
|
||||
} else {
|
||||
sendMessageDelayed(obtainMessage(MSG_POPUP_PREVIEW, keyIndex, 0, tracker), delay);
|
||||
sendMessageDelayed(
|
||||
obtainMessage(MSG_SHOW_KEY_PREVIEW, keyIndex, 0, tracker), delay);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelPopupPreview() {
|
||||
removeMessages(MSG_POPUP_PREVIEW);
|
||||
public void cancelShowKeyPreview(PointerTracker tracker) {
|
||||
removeMessages(MSG_SHOW_KEY_PREVIEW, tracker);
|
||||
}
|
||||
|
||||
public void dismissPreview(long delay) {
|
||||
sendMessageDelayed(obtainMessage(MSG_DISMISS_PREVIEW), delay);
|
||||
public void cancelAllShowKeyPreviews() {
|
||||
removeMessages(MSG_SHOW_KEY_PREVIEW);
|
||||
}
|
||||
|
||||
public void cancelDismissPreview() {
|
||||
removeMessages(MSG_DISMISS_PREVIEW);
|
||||
public void dismissKeyPreview(long delay, PointerTracker tracker) {
|
||||
sendMessageDelayed(obtainMessage(MSG_DISMISS_KEY_PREVIEW, tracker), delay);
|
||||
}
|
||||
|
||||
public void cancelDismissKeyPreview(PointerTracker tracker) {
|
||||
removeMessages(MSG_DISMISS_KEY_PREVIEW, tracker);
|
||||
}
|
||||
|
||||
public void cancelAllDismissKeyPreviews() {
|
||||
removeMessages(MSG_DISMISS_KEY_PREVIEW);
|
||||
}
|
||||
|
||||
public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) {
|
||||
|
@ -282,8 +289,8 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
|
||||
public void cancelAllMessages() {
|
||||
cancelKeyTimers();
|
||||
cancelPopupPreview();
|
||||
cancelDismissPreview();
|
||||
cancelAllShowKeyPreviews();
|
||||
cancelAllDismissKeyPreviews();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -363,18 +370,18 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
mPreviewText = (TextView) LayoutInflater.from(context).inflate(previewLayout, null);
|
||||
mPreviewTextSizeLarge = (int) res.getDimension(R.dimen.key_preview_text_size_large);
|
||||
} else {
|
||||
mShowPreview = false;
|
||||
mShowKeyPreview = false;
|
||||
}
|
||||
mDelayBeforePreview = res.getInteger(R.integer.config_delay_before_preview);
|
||||
mDelayAfterPreview = res.getInteger(R.integer.config_delay_after_preview);
|
||||
mKeyLabelHorizontalPadding = (int)res.getDimension(
|
||||
R.dimen.key_label_horizontal_alignment_padding);
|
||||
|
||||
mMiniKeyboardPopup = new PopupWindow(context);
|
||||
mMiniKeyboardPopup.setBackgroundDrawable(null);
|
||||
mMiniKeyboardPopup.setAnimationStyle(R.style.MiniKeyboardAnimation);
|
||||
mMiniKeyboardWindow = new PopupWindow(context);
|
||||
mMiniKeyboardWindow.setBackgroundDrawable(null);
|
||||
mMiniKeyboardWindow.setAnimationStyle(R.style.MiniKeyboardAnimation);
|
||||
// Allow popup window to be drawn off the screen.
|
||||
mMiniKeyboardPopup.setClippingEnabled(false);
|
||||
mMiniKeyboardWindow.setClippingEnabled(false);
|
||||
|
||||
mPaint = new Paint();
|
||||
mPaint.setAntiAlias(true);
|
||||
|
@ -484,11 +491,11 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
*/
|
||||
public void setKeyboard(Keyboard keyboard) {
|
||||
if (mKeyboard != null) {
|
||||
dismissKeyPreview();
|
||||
dismissAllKeyPreviews();
|
||||
}
|
||||
// Remove any pending messages, except dismissing preview
|
||||
mHandler.cancelKeyTimers();
|
||||
mHandler.cancelPopupPreview();
|
||||
mHandler.cancelAllShowKeyPreviews();
|
||||
mKeyboard = keyboard;
|
||||
LatinImeLogger.onSetKeyboard(keyboard);
|
||||
mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
|
||||
|
@ -544,33 +551,28 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the key feedback popup. This is a popup that shows a magnified
|
||||
* Enables or disables the key feedback preview. This is a preview that shows a magnified
|
||||
* version of the depressed key. By default the preview is enabled.
|
||||
* @param previewEnabled whether or not to enable the key feedback popup
|
||||
* @see #isPreviewEnabled()
|
||||
* @param previewEnabled whether or not to enable the key feedback preview
|
||||
* @see #isKeyPreviewEnabled()
|
||||
*/
|
||||
public void setPreviewEnabled(boolean previewEnabled) {
|
||||
mShowPreview = previewEnabled;
|
||||
public void setKeyPreviewEnabled(boolean previewEnabled) {
|
||||
mShowKeyPreview = previewEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enabled state of the key feedback popup.
|
||||
* @return whether or not the key feedback popup is enabled
|
||||
* @see #setPreviewEnabled(boolean)
|
||||
* Returns the enabled state of the key feedback preview
|
||||
* @return whether or not the key feedback preview is enabled
|
||||
* @see #setKeyPreviewEnabled(boolean)
|
||||
*/
|
||||
public boolean isPreviewEnabled() {
|
||||
return mShowPreview;
|
||||
public boolean isKeyPreviewEnabled() {
|
||||
return mShowKeyPreview;
|
||||
}
|
||||
|
||||
public int getColorScheme() {
|
||||
return mColorScheme;
|
||||
}
|
||||
|
||||
public void setPopupOffset(int x, int y) {
|
||||
mPopupPreviewOffsetX = x;
|
||||
mPopupPreviewOffsetY = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* When enabled, calls to {@link KeyboardActionListener#onCodeInput} will include key
|
||||
* codes for adjacent keys. When disabled, only the primary key code will be
|
||||
|
@ -878,47 +880,62 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
}
|
||||
|
||||
// TODO: clean up this method.
|
||||
private void dismissKeyPreview() {
|
||||
for (PointerTracker tracker : mPointerTrackers)
|
||||
tracker.releaseKey();
|
||||
showPreview(KeyDetector.NOT_A_KEY, null);
|
||||
private void dismissAllKeyPreviews() {
|
||||
for (PointerTracker tracker : mPointerTrackers) {
|
||||
tracker.setReleasedKeyGraphics();
|
||||
dismissKeyPreview(tracker);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPreview(int keyIndex, PointerTracker tracker) {
|
||||
int oldKeyIndex = mOldPreviewKeyIndex;
|
||||
mOldPreviewKeyIndex = keyIndex;
|
||||
if ((mShowPreview && oldKeyIndex != keyIndex) || mKeyboard.needSpacebarPreview(keyIndex)) {
|
||||
if (keyIndex == KeyDetector.NOT_A_KEY) {
|
||||
mHandler.cancelPopupPreview();
|
||||
mHandler.dismissPreview(mDelayAfterPreview);
|
||||
} else if (tracker != null) {
|
||||
mHandler.popupPreview(mDelayBeforePreview, keyIndex, tracker);
|
||||
public void showKeyPreview(int keyIndex, PointerTracker tracker) {
|
||||
if (mShowKeyPreview || mKeyboard.needSpacebarPreview(keyIndex)) {
|
||||
mHandler.showKeyPreview(mDelayBeforePreview, keyIndex, tracker);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismissKeyPreview(PointerTracker tracker) {
|
||||
if (mShowKeyPreview) {
|
||||
mHandler.cancelShowKeyPreview(tracker);
|
||||
mHandler.dismissKeyPreview(mDelayAfterPreview, tracker);
|
||||
}
|
||||
}
|
||||
|
||||
private void addKeyPreview(TextView keyPreview) {
|
||||
ViewGroup placer = mPreviewPlacer;
|
||||
if (placer == null) {
|
||||
final FrameLayout screenContent = (FrameLayout) getRootView().findViewById(
|
||||
android.R.id.content);
|
||||
if (android.os.Build.VERSION.SDK_INT >= /* HONEYCOMB */11) {
|
||||
placer = screenContent;
|
||||
} else {
|
||||
// Insert LinearLayout to be able to setMargin because pre-Honeycomb FrameLayout
|
||||
// could not handle setMargin properly.
|
||||
placer = new LinearLayout(getContext());
|
||||
screenContent.addView(placer);
|
||||
}
|
||||
mPreviewPlacer = placer;
|
||||
}
|
||||
if (placer instanceof FrameLayout) {
|
||||
placer.addView(keyPreview, new FrameLayout.LayoutParams(0, 0));
|
||||
} else {
|
||||
placer.addView(keyPreview, new LinearLayout.LayoutParams(0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Introduce minimum duration for displaying key previews
|
||||
// TODO: Display up to two key previews when the user presses two keys at the same time
|
||||
private void showKey(final int keyIndex, PointerTracker tracker) {
|
||||
// If the preview popup has no parent view yet, add it to the screen FrameLayout.
|
||||
// If the key preview has no parent view yet, add it to the ViewGroup which can place
|
||||
// key preview absolutely in SoftInputWindow.
|
||||
if (mPreviewText.getParent() == null) {
|
||||
final FrameLayout screenContent = (FrameLayout) getRootView()
|
||||
.findViewById(android.R.id.content);
|
||||
if (android.os.Build.VERSION.SDK_INT >= /* HONEYCOMB */ 11) {
|
||||
screenContent.addView(mPreviewText, new FrameLayout.LayoutParams(0, 0));
|
||||
} else {
|
||||
// Insert LinearLayout to be able to setMargin because pre-Honeycomb FrameLayout
|
||||
// could not handle setMargin properly.
|
||||
final LinearLayout placer = new LinearLayout(getContext());
|
||||
screenContent.addView(placer);
|
||||
placer.addView(mPreviewText, new LinearLayout.LayoutParams(0, 0));
|
||||
}
|
||||
addKeyPreview(mPreviewText);
|
||||
}
|
||||
|
||||
final Key key = tracker.getKey(keyIndex);
|
||||
// If keyIndex is invalid or IME is already closed, we must not show key preview.
|
||||
// Trying to show preview PopupWindow while root window is closed causes
|
||||
// Trying to show key preview while root window is closed causes
|
||||
// WindowManager.BadTokenException.
|
||||
if (key == null || !mInForeground)
|
||||
return;
|
||||
|
@ -942,37 +959,35 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
previewIcon != null ? previewIcon : key.getIcon());
|
||||
mPreviewText.setText(null);
|
||||
}
|
||||
mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
|
||||
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
|
||||
int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), keyDrawWidth
|
||||
+ mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight());
|
||||
final int popupHeight = mPreviewHeight;
|
||||
final ViewGroup.LayoutParams lp = mPreviewText.getLayoutParams();
|
||||
lp.width = popupWidth;
|
||||
lp.height = popupHeight;
|
||||
|
||||
int popupPreviewX = keyDrawX - (popupWidth - keyDrawWidth) / 2;
|
||||
int popupPreviewY = key.mY - popupHeight + mPreviewOffset;
|
||||
|
||||
mHandler.cancelDismissPreview();
|
||||
getLocationInWindow(mOffsetInWindow);
|
||||
mOffsetInWindow[0] += mPopupPreviewOffsetX; // Offset may be zero
|
||||
mOffsetInWindow[1] += mPopupPreviewOffsetY; // Offset may be zero
|
||||
|
||||
// Set the preview background state
|
||||
mPreviewText.getBackground().setState(
|
||||
key.mPopupCharacters != null ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET);
|
||||
popupPreviewX += mOffsetInWindow[0];
|
||||
popupPreviewY += mOffsetInWindow[1];
|
||||
|
||||
mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
|
||||
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
|
||||
int previewWidth = Math.max(mPreviewText.getMeasuredWidth(), keyDrawWidth
|
||||
+ mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight());
|
||||
final int previewHeight = mPreviewHeight;
|
||||
final ViewGroup.LayoutParams lp = mPreviewText.getLayoutParams();
|
||||
lp.width = previewWidth;
|
||||
lp.height = previewHeight;
|
||||
|
||||
int previewX = keyDrawX - (previewWidth - keyDrawWidth) / 2;
|
||||
int previewY = key.mY - previewHeight + mPreviewOffset;
|
||||
|
||||
mHandler.cancelAllDismissKeyPreviews();
|
||||
getLocationInWindow(mOffsetInWindow);
|
||||
previewX += mOffsetInWindow[0];
|
||||
previewY += mOffsetInWindow[1];
|
||||
|
||||
// Place the key preview.
|
||||
// TODO: Adjust position of key previews which touch screen edges
|
||||
if (lp instanceof ViewGroup.MarginLayoutParams) {
|
||||
ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)lp;
|
||||
mlp.setMargins(popupPreviewX, popupPreviewY, 0, 0);
|
||||
mlp.setMargins(previewX, previewY, 0, 0);
|
||||
}
|
||||
// Record popup preview position to display mini-keyboard later at the same position
|
||||
mPopupPreviewDisplayedY = popupPreviewY;
|
||||
// Record key preview position to display mini-keyboard later at the same position
|
||||
mKeyPreviewDisplayedY = previewY;
|
||||
mPreviewText.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
|
@ -1007,29 +1022,26 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
invalidate(mInvalidatedKeyRect);
|
||||
}
|
||||
|
||||
private boolean openPopupIfRequired(int keyIndex, PointerTracker tracker) {
|
||||
private boolean openMiniKeyboardIfRequired(int keyIndex, PointerTracker tracker) {
|
||||
// Check if we have a popup layout specified first.
|
||||
if (mPopupLayout == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Key popupKey = tracker.getKey(keyIndex);
|
||||
if (popupKey == null)
|
||||
Key parentKey = tracker.getKey(keyIndex);
|
||||
if (parentKey == null)
|
||||
return false;
|
||||
boolean result = onLongPress(popupKey, tracker);
|
||||
boolean result = onLongPress(parentKey, tracker);
|
||||
if (result) {
|
||||
dismissKeyPreview();
|
||||
dismissAllKeyPreviews();
|
||||
mMiniKeyboardTrackerId = tracker.mPointerId;
|
||||
// Mark this tracker "already processed" and remove it from the pointer queue
|
||||
tracker.setAlreadyProcessed();
|
||||
mPointerQueue.remove(tracker);
|
||||
tracker.onLongPressed(mPointerQueue);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void onLongPressShiftKey(PointerTracker tracker) {
|
||||
tracker.setAlreadyProcessed();
|
||||
mPointerQueue.remove(tracker);
|
||||
tracker.onLongPressed(mPointerQueue);
|
||||
mKeyboardActionListener.onCodeInput(Keyboard.CODE_CAPSLOCK, null, 0, 0);
|
||||
}
|
||||
|
||||
|
@ -1040,7 +1052,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
mKeyboardActionListener.onCodeInput(Keyboard.CODE_CAPSLOCK, null, 0, 0);
|
||||
}
|
||||
|
||||
private View inflateMiniKeyboardContainer(Key popupKey) {
|
||||
private View inflateMiniKeyboardContainer(Key parentKey) {
|
||||
final View container = LayoutInflater.from(getContext()).inflate(mPopupLayout, null);
|
||||
if (container == null)
|
||||
throw new NullPointerException();
|
||||
|
@ -1051,19 +1063,19 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
@Override
|
||||
public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
|
||||
mKeyboardActionListener.onCodeInput(primaryCode, keyCodes, x, y);
|
||||
dismissPopupKeyboard();
|
||||
dismissMiniKeyboard();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextInput(CharSequence text) {
|
||||
mKeyboardActionListener.onTextInput(text);
|
||||
dismissPopupKeyboard();
|
||||
dismissMiniKeyboard();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelInput() {
|
||||
mKeyboardActionListener.onCancelInput();
|
||||
dismissPopupKeyboard();
|
||||
dismissMiniKeyboard();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1085,7 +1097,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
miniKeyboardView.mGestureDetector = null;
|
||||
|
||||
final Keyboard keyboard = new MiniKeyboardBuilder(this, mKeyboard.getPopupKeyboardResId(),
|
||||
popupKey).build();
|
||||
parentKey).build();
|
||||
miniKeyboardView.setKeyboard(keyboard);
|
||||
|
||||
container.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),
|
||||
|
@ -1108,20 +1120,20 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
}
|
||||
|
||||
/**
|
||||
* Called when a key is long pressed. By default this will open any popup keyboard associated
|
||||
* Called when a key is long pressed. By default this will open any mini keyboard associated
|
||||
* with this key through the attributes popupLayout and popupCharacters.
|
||||
* @param popupKey the key that was long pressed
|
||||
* @param parentKey the key that was long pressed
|
||||
* @return true if the long press is handled, false otherwise. Subclasses should call the
|
||||
* method on the base class if the subclass doesn't wish to handle the call.
|
||||
*/
|
||||
protected boolean onLongPress(Key popupKey, PointerTracker tracker) {
|
||||
if (popupKey.mPopupCharacters == null)
|
||||
protected boolean onLongPress(Key parentKey, PointerTracker tracker) {
|
||||
if (parentKey.mPopupCharacters == null)
|
||||
return false;
|
||||
|
||||
View container = mMiniKeyboardCache.get(popupKey);
|
||||
View container = mMiniKeyboardCache.get(parentKey);
|
||||
if (container == null) {
|
||||
container = inflateMiniKeyboardContainer(popupKey);
|
||||
mMiniKeyboardCache.put(popupKey, container);
|
||||
container = inflateMiniKeyboardContainer(parentKey);
|
||||
mMiniKeyboardCache.put(parentKey, container);
|
||||
}
|
||||
mMiniKeyboardView = (KeyboardView)container.findViewById(R.id.KeyboardView);
|
||||
final MiniKeyboard miniKeyboard = (MiniKeyboard)mMiniKeyboardView.getKeyboard();
|
||||
|
@ -1131,36 +1143,35 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
getLocationInWindow(mWindowOffset);
|
||||
}
|
||||
final int pointX = (mConfigShowMiniKeyboardAtTouchedPoint) ? tracker.getLastX()
|
||||
: popupKey.mX + popupKey.mWidth / 2;
|
||||
final int popupX = pointX - miniKeyboard.getDefaultCoordX()
|
||||
: parentKey.mX + parentKey.mWidth / 2;
|
||||
final int miniKeyboardX = pointX - miniKeyboard.getDefaultCoordX()
|
||||
- container.getPaddingLeft()
|
||||
+ getPaddingLeft() + mWindowOffset[0];
|
||||
final int popupY = popupKey.mY - mKeyboard.getVerticalGap()
|
||||
final int miniKeyboardY = parentKey.mY - mKeyboard.getVerticalGap()
|
||||
- (container.getMeasuredHeight() - container.getPaddingBottom())
|
||||
+ getPaddingTop() + mWindowOffset[1];
|
||||
final int x = popupX;
|
||||
final int y = mShowPreview && isOneRowKeys(miniKeyboard.getKeys())
|
||||
? mPopupPreviewDisplayedY : popupY;
|
||||
final int x = miniKeyboardX;
|
||||
final int y = mShowKeyPreview && isOneRowKeys(miniKeyboard.getKeys())
|
||||
? mKeyPreviewDisplayedY : miniKeyboardY;
|
||||
|
||||
mMiniKeyboardOriginX = x + container.getPaddingLeft() - mWindowOffset[0];
|
||||
mMiniKeyboardOriginY = y + container.getPaddingTop() - mWindowOffset[1];
|
||||
mMiniKeyboardView.setPopupOffset(x, y);
|
||||
if (miniKeyboard.setShifted(
|
||||
mKeyboard == null ? false : mKeyboard.isShiftedOrShiftLocked())) {
|
||||
mMiniKeyboardView.invalidateAllKeys();
|
||||
}
|
||||
// Mini keyboard needs no pop-up key preview displayed.
|
||||
mMiniKeyboardView.setPreviewEnabled(false);
|
||||
mMiniKeyboardPopup.setContentView(container);
|
||||
mMiniKeyboardPopup.setWidth(container.getMeasuredWidth());
|
||||
mMiniKeyboardPopup.setHeight(container.getMeasuredHeight());
|
||||
mMiniKeyboardPopup.showAtLocation(this, Gravity.NO_GRAVITY, x, y);
|
||||
mMiniKeyboardView.setKeyPreviewEnabled(false);
|
||||
mMiniKeyboardWindow.setContentView(container);
|
||||
mMiniKeyboardWindow.setWidth(container.getMeasuredWidth());
|
||||
mMiniKeyboardWindow.setHeight(container.getMeasuredHeight());
|
||||
mMiniKeyboardWindow.showAtLocation(this, Gravity.NO_GRAVITY, x, y);
|
||||
|
||||
// Inject down event on the key to mini keyboard.
|
||||
final long eventTime = SystemClock.uptimeMillis();
|
||||
mMiniKeyboardPopupTime = eventTime;
|
||||
mMiniKeyboardDisplayedTime = eventTime;
|
||||
final MotionEvent downEvent = generateMiniKeyboardMotionEvent(MotionEvent.ACTION_DOWN,
|
||||
pointX, popupKey.mY + popupKey.mHeight / 2, eventTime);
|
||||
pointX, parentKey.mY + parentKey.mHeight / 2, eventTime);
|
||||
mMiniKeyboardView.onTouchEvent(downEvent);
|
||||
downEvent.recycle();
|
||||
|
||||
|
@ -1169,7 +1180,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
}
|
||||
|
||||
private MotionEvent generateMiniKeyboardMotionEvent(int action, int x, int y, long eventTime) {
|
||||
return MotionEvent.obtain(mMiniKeyboardPopupTime, eventTime, action,
|
||||
return MotionEvent.obtain(mMiniKeyboardDisplayedTime, eventTime, action,
|
||||
x - mMiniKeyboardOriginX, y - mMiniKeyboardOriginY, 0);
|
||||
}
|
||||
|
||||
|
@ -1180,7 +1191,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
// Create pointer trackers until we can get 'id+1'-th tracker, if needed.
|
||||
for (int i = pointers.size(); i <= id; i++) {
|
||||
final PointerTracker tracker =
|
||||
new PointerTracker(i, mHandler, mKeyDetector, this, getResources());
|
||||
new PointerTracker(i, this, mHandler, mKeyDetector, this);
|
||||
if (mKeyboard != null)
|
||||
tracker.setKeyboard(mKeyboard, mKeyHysteresisDistance);
|
||||
if (listener != null)
|
||||
|
@ -1226,7 +1237,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
// TODO: Reconcile gesture detection and accessibility features.
|
||||
if (mMiniKeyboardView == null && !mIsAccessibilityEnabled
|
||||
&& mGestureDetector != null && mGestureDetector.onTouchEvent(me)) {
|
||||
dismissKeyPreview();
|
||||
dismissAllKeyPreviews();
|
||||
mHandler.cancelKeyTimers();
|
||||
return true;
|
||||
}
|
||||
|
@ -1323,7 +1334,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
mPreviewText.setVisibility(View.GONE);
|
||||
mHandler.cancelAllMessages();
|
||||
|
||||
dismissPopupKeyboard();
|
||||
dismissMiniKeyboard();
|
||||
mDirtyRect.union(0, 0, getWidth(), getHeight());
|
||||
mMiniKeyboardCache.clear();
|
||||
requestLayout();
|
||||
|
@ -1340,9 +1351,9 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
closing();
|
||||
}
|
||||
|
||||
private void dismissPopupKeyboard() {
|
||||
if (mMiniKeyboardPopup.isShowing()) {
|
||||
mMiniKeyboardPopup.dismiss();
|
||||
private void dismissMiniKeyboard() {
|
||||
if (mMiniKeyboardWindow.isShowing()) {
|
||||
mMiniKeyboardWindow.dismiss();
|
||||
mMiniKeyboardView = null;
|
||||
mMiniKeyboardOriginX = 0;
|
||||
mMiniKeyboardOriginY = 0;
|
||||
|
@ -1351,8 +1362,8 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
|||
}
|
||||
|
||||
public boolean handleBack() {
|
||||
if (mMiniKeyboardPopup.isShowing()) {
|
||||
dismissPopupKeyboard();
|
||||
if (mMiniKeyboardWindow.isShowing()) {
|
||||
dismissMiniKeyboard();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -55,14 +55,14 @@ public class LatinKeyboardView extends KeyboardView {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setPreviewEnabled(boolean previewEnabled) {
|
||||
public void setKeyPreviewEnabled(boolean previewEnabled) {
|
||||
LatinKeyboard latinKeyboard = getLatinKeyboard();
|
||||
if (latinKeyboard != null
|
||||
&& (latinKeyboard.isPhoneKeyboard() || latinKeyboard.isNumberKeyboard())) {
|
||||
// Phone and number keyboard never shows popup preview (except language switch).
|
||||
super.setPreviewEnabled(false);
|
||||
super.setKeyPreviewEnabled(false);
|
||||
} else {
|
||||
super.setPreviewEnabled(previewEnabled);
|
||||
super.setKeyPreviewEnabled(previewEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,8 @@ public class PointerTracker {
|
|||
|
||||
public interface UIProxy {
|
||||
public void invalidateKey(Key key);
|
||||
public void showPreview(int keyIndex, PointerTracker tracker);
|
||||
public void showKeyPreview(int keyIndex, PointerTracker tracker);
|
||||
public void dismissKeyPreview(PointerTracker tracker);
|
||||
public boolean hasDistinctMultitouch();
|
||||
public boolean isAccessibilityEnabled();
|
||||
}
|
||||
|
@ -49,9 +50,7 @@ public class PointerTracker {
|
|||
private final int mLongPressKeyTimeout;
|
||||
private final int mLongPressShiftKeyTimeout;
|
||||
|
||||
// Miscellaneous constants
|
||||
private static final int NOT_A_KEY = KeyDetector.NOT_A_KEY;
|
||||
|
||||
private final KeyboardView mKeyboardView;
|
||||
private final UIProxy mProxy;
|
||||
private final UIHandler mHandler;
|
||||
private final KeyDetector mKeyDetector;
|
||||
|
@ -91,9 +90,6 @@ public class PointerTracker {
|
|||
// ignore modifier key if true
|
||||
private boolean mIgnoreModifierKey;
|
||||
|
||||
// pressed key
|
||||
private int mPreviousKey = NOT_A_KEY;
|
||||
|
||||
// Empty {@link KeyboardActionListener}
|
||||
private static final KeyboardActionListener EMPTY_LISTENER = new KeyboardActionListener() {
|
||||
@Override
|
||||
|
@ -110,11 +106,12 @@ public class PointerTracker {
|
|||
public void onSwipeDown() {}
|
||||
};
|
||||
|
||||
public PointerTracker(int id, UIHandler handler, KeyDetector keyDetector,
|
||||
UIProxy proxy, Resources res) {
|
||||
public PointerTracker(int id, KeyboardView keyboardView, UIHandler handler,
|
||||
KeyDetector keyDetector, UIProxy proxy) {
|
||||
if (proxy == null || handler == null || keyDetector == null)
|
||||
throw new NullPointerException();
|
||||
mPointerId = id;
|
||||
mKeyboardView = keyboardView;
|
||||
mProxy = proxy;
|
||||
mHandler = handler;
|
||||
mKeyDetector = keyDetector;
|
||||
|
@ -122,6 +119,7 @@ public class PointerTracker {
|
|||
mKeyState = new PointerTrackerKeyState(keyDetector);
|
||||
mIsAccessibilityEnabled = proxy.isAccessibilityEnabled();
|
||||
mHasDistinctMultitouch = proxy.hasDistinctMultitouch();
|
||||
final Resources res = mKeyboardView.getResources();
|
||||
mConfigSlidingKeyInputEnabled = res.getBoolean(R.bool.config_sliding_key_input_enabled);
|
||||
mDelayBeforeKeyRepeatStart = res.getInteger(R.integer.config_delay_before_key_repeat_start);
|
||||
mLongPressKeyTimeout = res.getInteger(R.integer.config_long_press_key_timeout);
|
||||
|
@ -250,29 +248,24 @@ public class PointerTracker {
|
|||
return key != null && key.mCode == Keyboard.CODE_SPACE;
|
||||
}
|
||||
|
||||
public void releaseKey() {
|
||||
updateKeyGraphics(NOT_A_KEY);
|
||||
public void setReleasedKeyGraphics() {
|
||||
setReleasedKeyGraphics(mKeyState.getKeyIndex());
|
||||
}
|
||||
|
||||
private void updateKeyGraphics(int keyIndex) {
|
||||
int oldKeyIndex = mPreviousKey;
|
||||
mPreviousKey = keyIndex;
|
||||
if (keyIndex != oldKeyIndex) {
|
||||
if (isValidKeyIndex(oldKeyIndex)) {
|
||||
final Key oldKey = mKeys.get(oldKeyIndex);
|
||||
oldKey.onReleased();
|
||||
mProxy.invalidateKey(oldKey);
|
||||
}
|
||||
if (isValidKeyIndex(keyIndex)) {
|
||||
final Key newKey = mKeys.get(keyIndex);
|
||||
newKey.onPressed();
|
||||
mProxy.invalidateKey(newKey);
|
||||
}
|
||||
private void setReleasedKeyGraphics(int keyIndex) {
|
||||
final Key key = getKey(keyIndex);
|
||||
if (key != null) {
|
||||
key.onReleased();
|
||||
mProxy.invalidateKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAlreadyProcessed() {
|
||||
mKeyAlreadyProcessed = true;
|
||||
private void setPressedKeyGraphics(int keyIndex) {
|
||||
final Key key = getKey(keyIndex);
|
||||
if (key != null && key.mEnabled) {
|
||||
key.onPressed();
|
||||
mProxy.invalidateKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAssertion(PointerTrackerQueue queue) {
|
||||
|
@ -318,7 +311,7 @@ public class PointerTracker {
|
|||
if (DEBUG_MODE)
|
||||
Log.w(TAG, "onDownEvent: ignore potential noise: time=" + deltaT
|
||||
+ " distance=" + distanceSquared);
|
||||
setAlreadyProcessed();
|
||||
mKeyAlreadyProcessed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -346,24 +339,25 @@ public class PointerTracker {
|
|||
mIsRepeatableKey = false;
|
||||
mIsInSlidingKeyInput = false;
|
||||
mIgnoreModifierKey = false;
|
||||
final Key key = getKey(keyIndex);
|
||||
if (key != null) {
|
||||
if (isValidKeyIndex(keyIndex)) {
|
||||
// This onPress call may have changed keyboard layout. Those cases are detected at
|
||||
// {@link #setKeyboard}. In those cases, we should update keyIndex according to the new
|
||||
// keyboard layout.
|
||||
if (callListenerOnPressAndCheckKeyboardLayoutChange(key, false))
|
||||
if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), false))
|
||||
keyIndex = mKeyState.onDownKey(x, y, eventTime);
|
||||
|
||||
// Accessibility disables key repeat because users may need to pause on a key to hear
|
||||
// its spoken description.
|
||||
if (key.mRepeatable && !mIsAccessibilityEnabled) {
|
||||
final Key key = getKey(keyIndex);
|
||||
if (key != null && key.mRepeatable && !mIsAccessibilityEnabled) {
|
||||
repeatKey(keyIndex);
|
||||
mHandler.startKeyRepeatTimer(mDelayBeforeKeyRepeatStart, keyIndex, this);
|
||||
mIsRepeatableKey = true;
|
||||
}
|
||||
startLongPressTimer(keyIndex);
|
||||
showKeyPreview(keyIndex);
|
||||
setPressedKeyGraphics(keyIndex);
|
||||
}
|
||||
showKeyPreviewAndUpdateKeyGraphics(keyIndex);
|
||||
}
|
||||
|
||||
private void startSlidingKeyInput(Key key) {
|
||||
|
@ -382,8 +376,9 @@ public class PointerTracker {
|
|||
|
||||
final int lastX = keyState.getLastX();
|
||||
final int lastY = keyState.getLastY();
|
||||
final int oldKeyIndex = keyState.getKeyIndex();
|
||||
final Key oldKey = getKey(oldKeyIndex);
|
||||
int keyIndex = keyState.onMoveKey(x, y);
|
||||
final Key oldKey = getKey(keyState.getKeyIndex());
|
||||
if (isValidKeyIndex(keyIndex)) {
|
||||
if (oldKey == null) {
|
||||
// The pointer has been slid in to the new key, but the finger was not on any keys.
|
||||
|
@ -395,10 +390,13 @@ public class PointerTracker {
|
|||
keyIndex = keyState.onMoveKey(x, y);
|
||||
keyState.onMoveToNewKey(keyIndex, x, y);
|
||||
startLongPressTimer(keyIndex);
|
||||
showKeyPreview(keyIndex);
|
||||
setPressedKeyGraphics(keyIndex);
|
||||
} else if (!isMinorMoveBounce(x, y, keyIndex)) {
|
||||
// The pointer has been slid in to the new key from the previous key, we must call
|
||||
// onRelease() first to notify that the previous key has been released, then call
|
||||
// onPress() to notify that the new key is being pressed.
|
||||
setReleasedKeyGraphics(oldKeyIndex);
|
||||
callListenerOnRelease(oldKey, oldKey.mCode, true);
|
||||
startSlidingKeyInput(oldKey);
|
||||
mHandler.cancelLongPressTimers();
|
||||
|
@ -410,6 +408,8 @@ public class PointerTracker {
|
|||
keyIndex = keyState.onMoveKey(x, y);
|
||||
keyState.onMoveToNewKey(keyIndex, x, y);
|
||||
startLongPressTimer(keyIndex);
|
||||
setPressedKeyGraphics(keyIndex);
|
||||
showKeyPreview(keyIndex);
|
||||
} else {
|
||||
// HACK: On some devices, quick successive touches may be translated to sudden
|
||||
// move by touch panel firmware. This hack detects the case and translates the
|
||||
|
@ -421,11 +421,12 @@ public class PointerTracker {
|
|||
if (DEBUG_MODE)
|
||||
Log.w(TAG, String.format("onMoveEvent: sudden move is translated to "
|
||||
+ "up[%d,%d]/down[%d,%d] events", lastX, lastY, x, y));
|
||||
onUpEventInternal(lastX, lastY, eventTime);
|
||||
onUpEventInternal(lastX, lastY, eventTime, true);
|
||||
onDownEventInternal(x, y, eventTime);
|
||||
} else {
|
||||
setAlreadyProcessed();
|
||||
showKeyPreviewAndUpdateKeyGraphics(NOT_A_KEY);
|
||||
mKeyAlreadyProcessed = true;
|
||||
dismissKeyPreview();
|
||||
setReleasedKeyGraphics(oldKeyIndex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -434,19 +435,19 @@ public class PointerTracker {
|
|||
if (oldKey != null && !isMinorMoveBounce(x, y, keyIndex)) {
|
||||
// The pointer has been slid out from the previous key, we must call onRelease() to
|
||||
// notify that the previous key has been released.
|
||||
setReleasedKeyGraphics(oldKeyIndex);
|
||||
callListenerOnRelease(oldKey, oldKey.mCode, true);
|
||||
startSlidingKeyInput(oldKey);
|
||||
mHandler.cancelLongPressTimers();
|
||||
if (mIsAllowedSlidingKeyInput) {
|
||||
keyState.onMoveToNewKey(keyIndex, x ,y);
|
||||
keyState.onMoveToNewKey(keyIndex, x, y);
|
||||
} else {
|
||||
setAlreadyProcessed();
|
||||
showKeyPreviewAndUpdateKeyGraphics(NOT_A_KEY);
|
||||
mKeyAlreadyProcessed = true;
|
||||
dismissKeyPreview();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
showKeyPreviewAndUpdateKeyGraphics(keyState.getKeyIndex());
|
||||
}
|
||||
|
||||
public void onUpEvent(int x, int y, long eventTime, PointerTrackerQueue queue) {
|
||||
|
@ -464,35 +465,48 @@ public class PointerTracker {
|
|||
}
|
||||
queue.remove(this);
|
||||
}
|
||||
onUpEventInternal(x, y, eventTime);
|
||||
onUpEventInternal(x, y, eventTime, true);
|
||||
}
|
||||
|
||||
public void onUpEventForRelease(int x, int y, long eventTime) {
|
||||
onUpEventInternal(x, y, eventTime);
|
||||
// Let this pointer tracker know that one of newer-than-this pointer trackers got an up event.
|
||||
// This pointer tracker needs to keep the key top graphics "pressed", but needs to get a
|
||||
// "virtual" up event.
|
||||
public void onPhantomUpEvent(int x, int y, long eventTime) {
|
||||
onUpEventInternal(x, y, eventTime, false);
|
||||
mKeyAlreadyProcessed = true;
|
||||
}
|
||||
|
||||
private void onUpEventInternal(int pointX, int pointY, long eventTime) {
|
||||
int x = pointX;
|
||||
int y = pointY;
|
||||
private void onUpEventInternal(int x, int y, long eventTime,
|
||||
boolean updateReleasedKeyGraphics) {
|
||||
mHandler.cancelKeyTimers();
|
||||
mHandler.cancelPopupPreview();
|
||||
showKeyPreviewAndUpdateKeyGraphics(NOT_A_KEY);
|
||||
mHandler.cancelShowKeyPreview(this);
|
||||
mIsInSlidingKeyInput = false;
|
||||
final PointerTrackerKeyState keyState = mKeyState;
|
||||
final int keyX, keyY;
|
||||
if (!isMinorMoveBounce(x, y, keyState.onMoveKey(x, y))) {
|
||||
keyX = x;
|
||||
keyY = y;
|
||||
} else {
|
||||
// Use previous fixed key coordinates.
|
||||
keyX = keyState.getKeyX();
|
||||
keyY = keyState.getKeyY();
|
||||
}
|
||||
final int keyIndex = keyState.onUpKey(keyX, keyY, eventTime);
|
||||
dismissKeyPreview();
|
||||
if (updateReleasedKeyGraphics)
|
||||
setReleasedKeyGraphics(keyIndex);
|
||||
if (mKeyAlreadyProcessed)
|
||||
return;
|
||||
final PointerTrackerKeyState keyState = mKeyState;
|
||||
int keyIndex = keyState.onUpKey(x, y, eventTime);
|
||||
if (isMinorMoveBounce(x, y, keyIndex)) {
|
||||
// Use previous fixed key index and coordinates.
|
||||
keyIndex = keyState.getKeyIndex();
|
||||
x = keyState.getKeyX();
|
||||
y = keyState.getKeyY();
|
||||
}
|
||||
if (!mIsRepeatableKey) {
|
||||
detectAndSendKey(keyIndex, x, y);
|
||||
detectAndSendKey(keyIndex, keyX, keyY);
|
||||
}
|
||||
}
|
||||
|
||||
public void onLongPressed(PointerTrackerQueue queue) {
|
||||
mKeyAlreadyProcessed = true;
|
||||
queue.remove(this);
|
||||
}
|
||||
|
||||
public void onCancelEvent(int x, int y, long eventTime, PointerTrackerQueue queue) {
|
||||
if (ENABLE_ASSERTION) checkAssertion(queue);
|
||||
if (DEBUG_EVENT)
|
||||
|
@ -505,8 +519,9 @@ public class PointerTracker {
|
|||
|
||||
private void onCancelEventInternal() {
|
||||
mHandler.cancelKeyTimers();
|
||||
mHandler.cancelPopupPreview();
|
||||
showKeyPreviewAndUpdateKeyGraphics(NOT_A_KEY);
|
||||
mHandler.cancelShowKeyPreview(this);
|
||||
dismissKeyPreview();
|
||||
setReleasedKeyGraphics(mKeyState.getKeyIndex());
|
||||
mIsInSlidingKeyInput = false;
|
||||
}
|
||||
|
||||
|
@ -542,7 +557,7 @@ public class PointerTracker {
|
|||
}
|
||||
}
|
||||
|
||||
private void showKeyPreviewAndUpdateKeyGraphics(int keyIndex) {
|
||||
private void showKeyPreview(int keyIndex) {
|
||||
final Key key = getKey(keyIndex);
|
||||
if (key != null && !key.mEnabled)
|
||||
return;
|
||||
|
@ -550,12 +565,13 @@ public class PointerTracker {
|
|||
// supported. On the other hand, if multi-touch is not supported, the modifier key should
|
||||
// be shown as preview. If accessibility is turned on, the modifier key should be shown as
|
||||
// preview.
|
||||
if (mHasDistinctMultitouch && isModifier() && !mIsAccessibilityEnabled) {
|
||||
mProxy.showPreview(NOT_A_KEY, this);
|
||||
} else {
|
||||
mProxy.showPreview(keyIndex, this);
|
||||
}
|
||||
updateKeyGraphics(keyIndex);
|
||||
if (mHasDistinctMultitouch && isModifier() && !mIsAccessibilityEnabled)
|
||||
return;
|
||||
mProxy.showKeyPreview(keyIndex, this);
|
||||
}
|
||||
|
||||
private void dismissKeyPreview() {
|
||||
mProxy.dismissKeyPreview(this);
|
||||
}
|
||||
|
||||
private void startLongPressTimer(int keyIndex) {
|
||||
|
|
|
@ -92,6 +92,7 @@ package com.android.inputmethod.keyboard;
|
|||
|
||||
public int onUpKey(int x, int y, long eventTime) {
|
||||
mUpTime = eventTime;
|
||||
mKeyIndex = KeyDetector.NOT_A_KEY;
|
||||
return onMoveKeyInternal(x, y);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,14 +29,13 @@ public class PointerTrackerQueue {
|
|||
if (mQueue.lastIndexOf(tracker) < 0) {
|
||||
return;
|
||||
}
|
||||
LinkedList<PointerTracker> queue = mQueue;
|
||||
final LinkedList<PointerTracker> queue = mQueue;
|
||||
int oldestPos = 0;
|
||||
for (PointerTracker t = queue.get(oldestPos); t != tracker; t = queue.get(oldestPos)) {
|
||||
if (t.isModifier()) {
|
||||
oldestPos++;
|
||||
} else {
|
||||
t.onUpEventForRelease(t.getLastX(), t.getLastY(), eventTime);
|
||||
t.setAlreadyProcessed();
|
||||
t.onPhantomUpEvent(t.getLastX(), t.getLastY(), eventTime);
|
||||
queue.remove(oldestPos);
|
||||
}
|
||||
}
|
||||
|
@ -50,8 +49,7 @@ public class PointerTrackerQueue {
|
|||
for (PointerTracker t : mQueue) {
|
||||
if (t == tracker)
|
||||
continue;
|
||||
t.onUpEventForRelease(t.getLastX(), t.getLastY(), eventTime);
|
||||
t.setAlreadyProcessed();
|
||||
t.onPhantomUpEvent(t.getLastX(), t.getLastY(), eventTime);
|
||||
}
|
||||
mQueue.clear();
|
||||
if (tracker != null)
|
||||
|
|
|
@ -162,36 +162,42 @@ public class InputLanguageSelection extends PreferenceActivity {
|
|||
for (int i = 0 ; i < origSize; i++ ) {
|
||||
String s = locales[i];
|
||||
int len = s.length();
|
||||
String language = "";
|
||||
String country = "";
|
||||
if (len == 5) {
|
||||
String language = s.substring(0, 2);
|
||||
String country = s.substring(3, 5);
|
||||
Locale l = new Locale(language, country);
|
||||
language = s.substring(0, 2);
|
||||
country = s.substring(3, 5);
|
||||
} else if (len < 5) {
|
||||
language = s;
|
||||
}
|
||||
Locale l = new Locale(language, country);
|
||||
|
||||
// Exclude languages that are not relevant to LatinIME
|
||||
if (arrayContains(BLACKLIST_LANGUAGES, language)) continue;
|
||||
// Exclude languages that are not relevant to LatinIME
|
||||
if (arrayContains(BLACKLIST_LANGUAGES, language) || TextUtils.isEmpty(language)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (finalSize == 0) {
|
||||
if (finalSize == 0) {
|
||||
preprocess[finalSize++] =
|
||||
new Loc(SubtypeSwitcher.getFullDisplayName(l, true), l);
|
||||
} else {
|
||||
// check previous entry:
|
||||
// same lang and a country -> upgrade to full name and
|
||||
// insert ours with full name
|
||||
// diff lang -> insert ours with lang-only name
|
||||
if (preprocess[finalSize-1].mLocale.getLanguage().equals(
|
||||
language)) {
|
||||
preprocess[finalSize-1].setLabel(SubtypeSwitcher.getFullDisplayName(
|
||||
preprocess[finalSize-1].mLocale, false));
|
||||
preprocess[finalSize++] =
|
||||
new Loc(SubtypeSwitcher.getFullDisplayName(l, true), l);
|
||||
new Loc(SubtypeSwitcher.getFullDisplayName(l, false), l);
|
||||
} else {
|
||||
// check previous entry:
|
||||
// same lang and a country -> upgrade to full name and
|
||||
// insert ours with full name
|
||||
// diff lang -> insert ours with lang-only name
|
||||
if (preprocess[finalSize-1].mLocale.getLanguage().equals(
|
||||
language)) {
|
||||
preprocess[finalSize-1].setLabel(SubtypeSwitcher.getFullDisplayName(
|
||||
preprocess[finalSize-1].mLocale, false));
|
||||
preprocess[finalSize++] =
|
||||
new Loc(SubtypeSwitcher.getFullDisplayName(l, false), l);
|
||||
String displayName;
|
||||
if (s.equals("zz_ZZ")) {
|
||||
// ignore this locale
|
||||
} else {
|
||||
String displayName;
|
||||
if (s.equals("zz_ZZ")) {
|
||||
// ignore this locale
|
||||
} else {
|
||||
displayName = SubtypeSwitcher.getFullDisplayName(l, true);
|
||||
preprocess[finalSize++] = new Loc(displayName, l);
|
||||
}
|
||||
displayName = SubtypeSwitcher.getFullDisplayName(l, true);
|
||||
preprocess[finalSize++] = new Loc(displayName, l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -592,7 +592,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
|||
|
||||
final boolean accessibilityEnabled = mAccessibilityUtils.isAccessibilityEnabled();
|
||||
|
||||
inputView.setPreviewEnabled(mPopupOn);
|
||||
inputView.setKeyPreviewEnabled(mPopupOn);
|
||||
inputView.setProximityCorrectionEnabled(true);
|
||||
inputView.setAccessibilityEnabled(accessibilityEnabled);
|
||||
// If we just entered a text field, maybe it has some old text that requires correction
|
||||
|
|
|
@ -417,6 +417,54 @@ inline static void multiplyRate(const int rate, int *freq) {
|
|||
}
|
||||
}
|
||||
|
||||
inline static int calcFreqForSplitTwoWords(
|
||||
const int typedLetterMultiplier, const int firstWordLength,
|
||||
const int secondWordLength, const int firstFreq, const int secondFreq) {
|
||||
if (firstWordLength == 0 || secondWordLength == 0) {
|
||||
return 0;
|
||||
}
|
||||
const int firstDemotionRate = 100 - 100 / (firstWordLength + 1);
|
||||
int tempFirstFreq = firstFreq;
|
||||
multiplyRate(firstDemotionRate, &tempFirstFreq);
|
||||
|
||||
const int secondDemotionRate = 100 - 100 / (secondWordLength + 1);
|
||||
int tempSecondFreq = secondFreq;
|
||||
multiplyRate(secondDemotionRate, &tempSecondFreq);
|
||||
|
||||
const int totalLength = firstWordLength + secondWordLength;
|
||||
|
||||
// Promote pairFreq with multiplying by 2, because the word length is the same as the typed
|
||||
// length.
|
||||
int totalFreq = tempFirstFreq + tempSecondFreq;
|
||||
|
||||
// This is a workaround to try offsetting the not-enough-demotion which will be done in
|
||||
// calcNormalizedScore in Utils.java.
|
||||
// In calcNormalizedScore the score will be demoted by (1 - 1 / length)
|
||||
// but we demoted only (1 - 1 / (length + 1)) so we will additionally adjust freq by
|
||||
// (1 - 1 / length) / (1 - 1 / (length + 1)) = (1 - 1 / (length * length))
|
||||
const int normalizedScoreNotEnoughDemotionAdjustment = 100 - 100 / (totalLength * totalLength);
|
||||
multiplyRate(normalizedScoreNotEnoughDemotionAdjustment, &totalFreq);
|
||||
|
||||
// At this moment, totalFreq is calculated by the following formula:
|
||||
// (firstFreq * (1 - 1 / (firstWordLength + 1)) + secondFreq * (1 - 1 / (secondWordLength + 1)))
|
||||
// * (1 - 1 / totalLength) / (1 - 1 / (totalLength + 1))
|
||||
|
||||
for (int i = 0; i < totalLength; ++i) {
|
||||
totalFreq *= typedLetterMultiplier;
|
||||
}
|
||||
|
||||
// This is another workaround to offset the demotion which will be done in
|
||||
// calcNormalizedScore in Utils.java.
|
||||
// In calcNormalizedScore the score will be demoted by (1 - 1 / length) so we have to promote
|
||||
// the same amount because we already have adjusted the synthetic freq of this "missing or
|
||||
// mistyped space" suggestion candidate above in this method.
|
||||
const int normalizedScoreDemotionRateOffset = (100 + 100 / totalLength);
|
||||
multiplyRate(normalizedScoreDemotionRateOffset, &totalFreq);
|
||||
|
||||
multiplyRate(WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE, &totalFreq);
|
||||
return totalFreq;
|
||||
}
|
||||
|
||||
bool UnigramDictionary::getSplitTwoWordsSuggestion(const int inputLength,
|
||||
const int firstWordStartPos, const int firstWordLength, const int secondWordStartPos,
|
||||
const int secondWordLength) {
|
||||
|
@ -448,15 +496,12 @@ bool UnigramDictionary::getSplitTwoWordsSuggestion(const int inputLength,
|
|||
word[i] = mWord[i - firstWordLength - 1];
|
||||
}
|
||||
|
||||
// Promote pairFreq with multiplying by 2, because the word length is the same as the typed
|
||||
// length.
|
||||
int pairFreq = firstFreq + secondFreq;
|
||||
for (int i = 0; i < inputLength; ++i) pairFreq *= TYPED_LETTER_MULTIPLIER;
|
||||
int pairFreq = calcFreqForSplitTwoWords(
|
||||
TYPED_LETTER_MULTIPLIER, firstWordLength, secondWordLength, firstFreq, secondFreq);
|
||||
if (DEBUG_DICT) {
|
||||
LOGI("Missing space: %d, %d, %d, %d, %d", firstFreq, secondFreq, pairFreq, inputLength,
|
||||
TYPED_LETTER_MULTIPLIER);
|
||||
}
|
||||
multiplyRate(WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE, &pairFreq);
|
||||
addWord(word, newWordLength, pairFreq);
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue