diff options
Diffstat (limited to 'java/src')
8 files changed, 190 insertions, 88 deletions
diff --git a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java new file mode 100644 index 000000000..dec739d39 --- /dev/null +++ b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.compat; + +import android.view.View; + +import java.lang.reflect.Method; + +// TODO: Use {@link android.support.v4.view.ViewCompat} instead of this utility class. +// Currently {@link #getPaddingEnd(View)} and {@link #setPaddingRelative(View,int,int,int,int)} +// are missing from android-support-v4 static library in KitKat SDK. +public final class ViewCompatUtils { + // Note that View.LAYOUT_DIRECTION_LTR and View.LAYOUT_DIRECTION_RTL have been introduced in + // API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1). + public static final int LAYOUT_DIRECTION_LTR = (Integer)CompatUtils.getFieldValue(null, 0x0, + CompatUtils.getField(View.class, "LAYOUT_DIRECTION_LTR")); + public static final int LAYOUT_DIRECTION_RTL = (Integer)CompatUtils.getFieldValue(null, 0x1, + CompatUtils.getField(View.class, "LAYOUT_DIRECTION_RTL")); + + // Note that View.getPaddingEnd(), View.setPaddingRelative(int,int,int,int), and + // View.getLayoutDirection() have been introduced in API level 17 + // (Build.VERSION_CODE.JELLY_BEAN_MR1). + private static final Method METHOD_getPaddingEnd = CompatUtils.getMethod( + View.class, "getPaddingEnd"); + private static final Method METHOD_setPaddingRelative = CompatUtils.getMethod( + View.class, "setPaddingRelative", + Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE); + private static final Method METHOD_getLayoutDirection = CompatUtils.getMethod( + View.class, "getLayoutDirection"); + + private ViewCompatUtils() { + // This utility class is not publicly instantiable. + } + + public static int getPaddingEnd(final View view) { + if (METHOD_getPaddingEnd == null) { + return view.getPaddingRight(); + } + return (Integer)CompatUtils.invoke(view, 0, METHOD_getPaddingEnd); + } + + public static void setPaddingRelative(final View view, final int start, final int top, + final int end, final int bottom) { + if (METHOD_setPaddingRelative == null) { + view.setPadding(start, top, end, bottom); + return; + } + CompatUtils.invoke(view, null, METHOD_setPaddingRelative, start, top, end, bottom); + } + + public static int getLayoutDirection(final View view) { + if (METHOD_getLayoutDirection == null) { + return LAYOUT_DIRECTION_LTR; + } + return (Integer)CompatUtils.invoke(view, 0, METHOD_getLayoutDirection); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java index 8dea908e8..5bde668e1 100644 --- a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java +++ b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java @@ -23,12 +23,13 @@ import android.content.SharedPreferences; import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; +import android.graphics.Color; import android.graphics.Rect; import android.os.Build; +import android.os.CountDownTimer; import android.preference.PreferenceManager; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; -import android.text.format.DateUtils; import android.util.AttributeSet; import android.util.Log; import android.util.Pair; @@ -58,6 +59,7 @@ import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; /** * View class to implement Emoji palettes. @@ -752,9 +754,8 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } } - // TODO: Do the same things done in PointerTracker private static class DeleteKeyOnTouchListener implements OnTouchListener { - private static final long MAX_REPEAT_COUNT_TIME = 30 * DateUtils.SECOND_IN_MILLIS; + private static final long MAX_REPEAT_COUNT_TIME = TimeUnit.SECONDS.toMillis(30); private final int mDeleteKeyPressedBackgroundColor; private final long mKeyRepeatStartTimeout; private final long mKeyRepeatInterval; @@ -765,80 +766,117 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange res.getColor(R.color.emoji_key_pressed_background_color); mKeyRepeatStartTimeout = res.getInteger(R.integer.config_key_repeat_start_timeout); mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval); + mTimer = new CountDownTimer(MAX_REPEAT_COUNT_TIME, mKeyRepeatInterval) { + @Override + public void onTick(long millisUntilFinished) { + final long elapsed = MAX_REPEAT_COUNT_TIME - millisUntilFinished; + if (elapsed < mKeyRepeatStartTimeout) { + return; + } + onKeyRepeat(); + } + @Override + public void onFinish() { + onKeyRepeat(); + } + }; } + /** Key-repeat state. */ + private static final int KEY_REPEAT_STATE_INITIALIZED = 0; + // The key is touched but auto key-repeat is not started yet. + private static final int KEY_REPEAT_STATE_KEY_DOWN = 1; + // At least one key-repeat event has already been triggered and the key is not released. + private static final int KEY_REPEAT_STATE_KEY_REPEAT = 2; + private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER; - private DummyRepeatKeyRepeatTimer mTimer; - private synchronized void startRepeat() { - if (mTimer != null) { - abortRepeat(); - } - mTimer = new DummyRepeatKeyRepeatTimer(); - mTimer.start(); - } + // TODO: Do the same things done in PointerTracker + private final CountDownTimer mTimer; + private int mState = KEY_REPEAT_STATE_INITIALIZED; + private int mRepeatCount = 0; - private synchronized void abortRepeat() { - mTimer.abort(); - mTimer = null; + public void setKeyboardActionListener(final KeyboardActionListener listener) { + mKeyboardActionListener = listener; } - // TODO: Remove - // This function is mimicking the repeat code in PointerTracker. - // Specifically referring to PointerTracker#startRepeatKey and PointerTracker#onKeyRepeat. - private class DummyRepeatKeyRepeatTimer extends Thread { - public boolean mAborted = false; - - @Override - public void run() { - int repeatCount = 1; - int timeCount = 0; - while (timeCount < MAX_REPEAT_COUNT_TIME && !mAborted) { - if (timeCount > mKeyRepeatStartTimeout) { - pressDelete(repeatCount); - } - timeCount += mKeyRepeatInterval; - ++repeatCount; - try { - Thread.sleep(mKeyRepeatInterval); - } catch (InterruptedException e) { - } + @Override + public boolean onTouch(final View v, final MotionEvent event) { + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + onTouchDown(v); + return true; + case MotionEvent.ACTION_MOVE: + final float x = event.getX(); + final float y = event.getY(); + if (x < 0.0f || v.getWidth() < x || y < 0.0f || v.getHeight() < y) { + // Stop generating key events once the finger moves away from the view area. + onTouchCanceled(v); } + return true; + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + onTouchUp(v); + return true; } - - public void abort() { - mAborted = true; - } + return false; } - public void pressDelete(final int repeatCount) { + private void handleKeyDown() { mKeyboardActionListener.onPressKey( - Constants.CODE_DELETE, repeatCount, true /* isSinglePointer */); + Constants.CODE_DELETE, mRepeatCount, true /* isSinglePointer */); + } + + private void handleKeyUp() { mKeyboardActionListener.onCodeInput( Constants.CODE_DELETE, NOT_A_COORDINATE, NOT_A_COORDINATE); mKeyboardActionListener.onReleaseKey( Constants.CODE_DELETE, false /* withSliding */); + ++mRepeatCount; } - public void setKeyboardActionListener(final KeyboardActionListener listener) { - mKeyboardActionListener = listener; + private void onTouchDown(final View v) { + mTimer.cancel(); + mRepeatCount = 0; + handleKeyDown(); + v.setBackgroundColor(mDeleteKeyPressedBackgroundColor); + mState = KEY_REPEAT_STATE_KEY_DOWN; + mTimer.start(); } - @Override - public boolean onTouch(final View v, final MotionEvent event) { - switch(event.getAction()) { - case MotionEvent.ACTION_DOWN: - v.setBackgroundColor(mDeleteKeyPressedBackgroundColor); - pressDelete(0 /* repeatCount */); - startRepeat(); - return true; - case MotionEvent.ACTION_UP: - v.setBackgroundColor(0); - abortRepeat(); - return true; + private void onTouchUp(final View v) { + mTimer.cancel(); + if (mState == KEY_REPEAT_STATE_KEY_DOWN) { + handleKeyUp(); + } + v.setBackgroundColor(Color.TRANSPARENT); + mState = KEY_REPEAT_STATE_INITIALIZED; + } + + private void onTouchCanceled(final View v) { + mTimer.cancel(); + v.setBackgroundColor(Color.TRANSPARENT); + mState = KEY_REPEAT_STATE_INITIALIZED; + } + + // Called by {@link #mTimer} in the UI thread as an auto key-repeat signal. + private void onKeyRepeat() { + switch (mState) { + case KEY_REPEAT_STATE_INITIALIZED: + // Basically this should not happen. + break; + case KEY_REPEAT_STATE_KEY_DOWN: + // Do not call {@link #handleKeyDown} here because it has already been called + // in {@link #onTouchDown}. + handleKeyUp(); + mState = KEY_REPEAT_STATE_KEY_REPEAT; + break; + case KEY_REPEAT_STATE_KEY_REPEAT: + handleKeyDown(); + handleKeyUp(); + break; } - return false; } } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index bba9bd52c..82d824b8f 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -888,10 +888,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mInputLogic.finishInput(); // Notify ResearchLogger if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_onFinishInputViewInternal(finishingInput, - // TODO[IL]: mInputLogic.mConnection should be private - mInputLogic.mConnection.getExpectedSelectionStart(), - mInputLogic.mConnection.getExpectedSelectionEnd(), getCurrentInputConnection()); + ResearchLogger.latinIME_onFinishInputViewInternal(finishingInput); } } @@ -1186,7 +1183,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // the right layout. // TODO[IL]: Remove this, pass the input logic to the keyboard switcher instead? public int getCurrentAutoCapsState() { - return mInputLogic.getCurrentAutoCapsState(null /* optionalSettingsValues */); + return mInputLogic.getCurrentAutoCapsState(Settings.getInstance().getCurrent()); } // Called from the KeyboardSwitcher which needs to know recaps state to display @@ -1288,8 +1285,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } else { codeToSend = codePoint; } - mInputLogic.onCodeInput(codeToSend, keyX, keyY, mHandler, mKeyboardSwitcher, - mSubtypeSwitcher); + if (Constants.CODE_SHORTCUT == codePoint) { + mSubtypeSwitcher.switchToShortcutIME(this); + // Still call the *#onCodeInput methods for readability. + } + mInputLogic.onCodeInput(codeToSend, keyX, keyY, Settings.getInstance().getCurrent(), + mHandler, mKeyboardSwitcher); mKeyboardSwitcher.onCodeInput(codePoint); } diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 6e9bdc34a..6e3543216 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -36,14 +36,12 @@ import com.android.inputmethod.latin.LastComposedWord; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.RichInputConnection; -import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.Suggest; import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.WordComposer; import com.android.inputmethod.latin.define.ProductionFlag; -import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.settings.SettingsValues; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.utils.AsyncResultHolder; @@ -192,13 +190,12 @@ public final class InputLogic { * @param y the y-coordinate where the user pressed the key, or NOT_A_COORDINATE. */ public void onCodeInput(final int code, final int x, final int y, - // TODO: remove these three arguments - final LatinIME.UIHandler handler, - final KeyboardSwitcher keyboardSwitcher, final SubtypeSwitcher subtypeSwitcher) { + final SettingsValues settingsValues, + // TODO: remove these two arguments + final LatinIME.UIHandler handler, final KeyboardSwitcher keyboardSwitcher) { if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.latinIME_onCodeInput(code, x, y); } - final SettingsValues settingsValues = Settings.getInstance().getCurrent(); final long when = SystemClock.uptimeMillis(); if (code != Constants.CODE_DELETE || when > mLastKeyTime + Constants.LONG_PRESS_MILLISECONDS) { @@ -247,7 +244,8 @@ public final class InputLogic { onSettingsKeyPressed(); break; case Constants.CODE_SHORTCUT: - subtypeSwitcher.switchToShortcutIME(mLatinIME); + // We need to switch to the shortcut IME. This is handled by LatinIME since the + // input logic has no business with IME switching. break; case Constants.CODE_ACTION_NEXT: performEditorAction(EditorInfo.IME_ACTION_NEXT); @@ -1256,15 +1254,10 @@ public final class InputLogic { * This is called from the KeyboardSwitcher (through a trampoline in LatinIME) because it * needs to know auto caps state to display the right layout. * - * @param optionalSettingsValues settings values, or null if we should just get the current ones - * from the singleton. + * @param settingsValues the relevant settings values * @return a caps mode from TextUtils.CAP_MODE_* or Constants.TextUtils.CAP_MODE_OFF. */ - public int getCurrentAutoCapsState(final SettingsValues optionalSettingsValues) { - // If we are in a batch edit, we need to use the same settings values as the outside - // code, that will pass it to us. Otherwise, we can just take the current values. - final SettingsValues settingsValues = null != optionalSettingsValues - ? optionalSettingsValues : Settings.getInstance().getCurrent(); + public int getCurrentAutoCapsState(final SettingsValues settingsValues) { if (!settingsValues.mAutoCap) return Constants.TextUtils.CAP_MODE_OFF; final EditorInfo ei = getCurrentInputEditorInfo(); diff --git a/java/src/com/android/inputmethod/latin/setup/SetupStartIndicatorView.java b/java/src/com/android/inputmethod/latin/setup/SetupStartIndicatorView.java index 73d25f6aa..974dfddd3 100644 --- a/java/src/com/android/inputmethod/latin/setup/SetupStartIndicatorView.java +++ b/java/src/com/android/inputmethod/latin/setup/SetupStartIndicatorView.java @@ -21,13 +21,13 @@ import android.content.res.ColorStateList; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; -import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; +import com.android.inputmethod.compat.ViewCompatUtils; import com.android.inputmethod.latin.R; public final class SetupStartIndicatorView extends LinearLayout { @@ -96,13 +96,13 @@ public final class SetupStartIndicatorView extends LinearLayout { @Override protected void onDraw(final Canvas canvas) { super.onDraw(canvas); - final int layoutDirection = ViewCompat.getLayoutDirection(this); + final int layoutDirection = ViewCompatUtils.getLayoutDirection(this); final int width = getWidth(); final int height = getHeight(); final float halfHeight = height / 2.0f; final Path path = mIndicatorPath; path.rewind(); - if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL) { + if (layoutDirection == ViewCompatUtils.LAYOUT_DIRECTION_RTL) { // Left arrow path.moveTo(width, 0.0f); path.lineTo(0.0f, halfHeight); diff --git a/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java b/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java index 6734e61b8..c909507c6 100644 --- a/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java +++ b/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java @@ -20,10 +20,10 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; -import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.view.View; +import com.android.inputmethod.compat.ViewCompatUtils; import com.android.inputmethod.latin.R; public final class SetupStepIndicatorView extends View { @@ -38,12 +38,12 @@ public final class SetupStepIndicatorView extends View { } public void setIndicatorPosition(final int stepPos, final int totalStepNum) { - final int layoutDirection = ViewCompat.getLayoutDirection(this); + final int layoutDirection = ViewCompatUtils.getLayoutDirection(this); // The indicator position is the center of the partition that is equally divided into // the total step number. final float partionWidth = 1.0f / totalStepNum; final float pos = stepPos * partionWidth + partionWidth / 2.0f; - mXRatio = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL) ? 1.0f - pos : pos; + mXRatio = (layoutDirection == ViewCompatUtils.LAYOUT_DIRECTION_RTL) ? 1.0f - pos : pos; invalidate(); } diff --git a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java index baff57a1c..5072fabd6 100644 --- a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java +++ b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java @@ -25,7 +25,6 @@ import android.net.Uri; import android.os.Bundle; import android.os.Message; import android.provider.Settings; -import android.support.v4.view.ViewCompat; import android.util.Log; import android.view.View; import android.view.inputmethod.InputMethodInfo; @@ -35,6 +34,7 @@ import android.widget.TextView; import android.widget.VideoView; import com.android.inputmethod.compat.TextViewCompatUtils; +import com.android.inputmethod.compat.ViewCompatUtils; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.settings.SettingsActivity; import com.android.inputmethod.latin.utils.CollectionUtils; @@ -449,8 +449,8 @@ public final class SetupWizardActivity extends Activity implements View.OnClickL mActionLabel = (TextView)mStepView.findViewById(R.id.setup_step_action_label); mActionLabel.setText(res.getString(actionLabel)); if (actionIcon == 0) { - final int paddingEnd = ViewCompat.getPaddingEnd(mActionLabel); - ViewCompat.setPaddingRelative(mActionLabel, paddingEnd, 0, paddingEnd, 0); + final int paddingEnd = ViewCompatUtils.getPaddingEnd(mActionLabel); + ViewCompatUtils.setPaddingRelative(mActionLabel, paddingEnd, 0, paddingEnd, 0); } else { TextViewCompatUtils.setCompoundDrawablesRelativeWithIntrinsicBounds( mActionLabel, res.getDrawable(actionIcon), null, null, null); diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index 2a8148d02..b1f54c0b4 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -1117,14 +1117,13 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final LogStatement LOGSTATEMENT_LATINIME_ONFINISHINPUTVIEWINTERNAL = new LogStatement("LatinIMEOnFinishInputViewInternal", false, false, "isTextTruncated", "text"); - public static void latinIME_onFinishInputViewInternal(final boolean finishingInput, - final int savedSelectionStart, final int savedSelectionEnd, final InputConnection ic) { + public static void latinIME_onFinishInputViewInternal(final boolean finishingInput) { // The finishingInput flag is set in InputMethodService. It is true if called from // doFinishInput(), which can be called as part of doStartInput(). This can happen at times // when the IME is not closing, such as when powering up. The finishinInput flag is false // if called from finishViews(), which is called from hideWindow() and onDestroy(). These // are the situations in which we want to finish up the researchLog. - if (ic != null && !finishingInput) { + if (!finishingInput) { final ResearchLogger researchLogger = getInstance(); // Assume that OUTPUT_ENTIRE_BUFFER is only true when we don't care about privacy (e.g. // during a live user test), so the normal isPotentiallyPrivate and |