diff options
Diffstat (limited to 'java/src')
7 files changed, 279 insertions, 13 deletions
diff --git a/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java b/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java new file mode 100644 index 000000000..2cec14240 --- /dev/null +++ b/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2014 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.graphics.Matrix; +import android.graphics.RectF; + +import com.android.inputmethod.annotations.UsedForTesting; + +import java.lang.reflect.Method; + +@UsedForTesting +public final class CursorAnchorInfoCompatWrapper { + // Note that CursorAnchorInfo has been introduced in API level XX (Build.VERSION_CODE.LXX). + private static Class<?> getCursorAnchorInfoClass() { + try { + return Class.forName("android.view.inputmethod.CursorAnchorInfo"); + } catch (ClassNotFoundException e) { + return null; + } + } + private static final Class<?> CLASS; + private static final Method METHOD_GET_CHARACTER_RECT; + private static final Method METHOD_GET_CHARACTER_RECT_FLAGS; + private static final Method METHOD_GET_COMPOSING_TEXT; + private static final Method METHOD_GET_COMPOSING_TEXT_START; + private static final Method METHOD_GET_MATRIX; + static { + CLASS = getCursorAnchorInfoClass(); + METHOD_GET_CHARACTER_RECT = CompatUtils.getMethod(CLASS, "getCharacterRect", int.class); + METHOD_GET_CHARACTER_RECT_FLAGS = CompatUtils.getMethod(CLASS, "getCharacterRectFlags", + int.class); + METHOD_GET_COMPOSING_TEXT = CompatUtils.getMethod(CLASS, "getComposingText"); + METHOD_GET_COMPOSING_TEXT_START = CompatUtils.getMethod(CLASS, "getComposingTextStart"); + METHOD_GET_MATRIX = CompatUtils.getMethod(CLASS, "getMatrix"); + } + + @UsedForTesting + public static boolean isAvailable() { + return CLASS != null; + } + + public static final int CHARACTER_RECT_TYPE_MASK = 0x0f; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor did not specify any type of this + * character. Editor authors should not use this flag. + */ + public static final int CHARACTER_RECT_TYPE_UNSPECIFIED = 0; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely visible. + */ + public static final int CHARACTER_RECT_TYPE_FULLY_VISIBLE = 1; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: some area of the character is invisible. + */ + public static final int CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE = 2; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely invisible. + */ + public static final int CHARACTER_RECT_TYPE_INVISIBLE = 3; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor gave up to calculate the rectangle + * for this character. Input method authors should ignore the returned rectangle. + */ + public static final int CHARACTER_RECT_TYPE_NOT_FEASIBLE = 4; + + private Object mInstance; + + private CursorAnchorInfoCompatWrapper(final Object instance) { + mInstance = instance; + } + + @UsedForTesting + public static CursorAnchorInfoCompatWrapper fromObject(final Object instance) { + if (!isAvailable()) { + return new CursorAnchorInfoCompatWrapper(null); + } + return new CursorAnchorInfoCompatWrapper(instance); + } + + private static final class FakeHolder { + static CursorAnchorInfoCompatWrapper sInstance = new CursorAnchorInfoCompatWrapper(null); + } + + @UsedForTesting + public static CursorAnchorInfoCompatWrapper getFake() { + return FakeHolder.sInstance; + } + + public CharSequence getComposingText() { + return (CharSequence) CompatUtils.invoke(mInstance, null, METHOD_GET_COMPOSING_TEXT); + } + + private static int COMPOSING_TEXT_START_DEFAULT = -1; + public int getComposingTextStart() { + if (mInstance == null || METHOD_GET_COMPOSING_TEXT_START == null) { + return COMPOSING_TEXT_START_DEFAULT; + } + return (int) CompatUtils.invoke(mInstance, null, METHOD_GET_COMPOSING_TEXT_START); + } + + public Matrix getMatrix() { + return (Matrix) CompatUtils.invoke(mInstance, null, METHOD_GET_MATRIX); + } + + public RectF getCharacterRect(final int index) { + return (RectF) CompatUtils.invoke(mInstance, null, METHOD_GET_CHARACTER_RECT, index); + } + + public int getCharacterRectFlags(final int index) { + if (mInstance == null || METHOD_GET_CHARACTER_RECT_FLAGS == null) { + return CHARACTER_RECT_TYPE_UNSPECIFIED; + } + return (int) CompatUtils.invoke(mInstance, null, METHOD_GET_CHARACTER_RECT_FLAGS, index); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index f35126750..140e76879 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -18,6 +18,7 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.SharedPreferences; +import android.content.res.Configuration; import android.content.res.Resources; import android.preference.PreferenceManager; import android.util.Log; @@ -233,11 +234,21 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { } private void setMainKeyboardFrame() { - mMainKeyboardFrame.setVisibility(View.VISIBLE); + mMainKeyboardFrame.setVisibility(hasHardwareKeyboard() ? View.GONE : View.VISIBLE); mEmojiPalettesView.setVisibility(View.GONE); mEmojiPalettesView.stopEmojiPalettes(); } + // TODO: Move this boolean to a member of {@link SettingsValues} and reset it + // at {@link LatinIME#onConfigurationChanged(Configuration)}. + public boolean hasHardwareKeyboard() { + // Copied from {@link InputMethodServce#onEvaluateInputViewShown()}. + final Configuration config = mLatinIME.getResources().getConfiguration(); + final boolean noHardwareKeyboard = config.keyboard == Configuration.KEYBOARD_NOKEYS + || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES; + return !noHardwareKeyboard; + } + // Implements {@link KeyboardState.SwitchActions}. @Override public void setEmojiKeyboard() { @@ -249,6 +260,14 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { mEmojiPalettesView.setVisibility(View.VISIBLE); } + public void onToggleEmojiKeyboard() { + if (isShowingEmojiPalettes()) { + setAlphabetKeyboard(); + } else { + setEmojiKeyboard(); + } + } + // Implements {@link KeyboardState.SwitchActions}. @Override public void setSymbolsShiftedKeyboard() { diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java index 4c2e0dd1d..135423393 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java @@ -38,6 +38,9 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> { public static final int THEME_ID_LXX_DARK = 4; public static final int DEFAULT_THEME_ID = THEME_ID_KLP; + // TODO: Update this constant once the *next* version becomes available. + public static final int VERSION_CODES_LXX = 21; + private static final KeyboardTheme[] KEYBOARD_THEMES = { new KeyboardTheme(THEME_ID_ICS, R.style.KeyboardTheme_ICS, // This has never been selected because we support ICS or later. @@ -47,8 +50,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> { VERSION_CODES.ICE_CREAM_SANDWICH), new KeyboardTheme(THEME_ID_LXX_LIGHT, R.style.KeyboardTheme_LXX_Light, // Default theme for LXX. - // TODO: Update this constant once the *next* version becomes available. - VERSION_CODES.CUR_DEVELOPMENT), + VERSION_CODES_LXX), new KeyboardTheme(THEME_ID_LXX_DARK, R.style.KeyboardTheme_LXX_Dark, VERSION_CODES.BASE), }; @@ -100,12 +102,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> { } private static int getSdkVersion() { - final int sdkVersion = Build.VERSION.SDK_INT; - // TODO: Consider to remove this check once the *next* version becomes available. - if (sdkVersion > VERSION_CODES.KITKAT) { - return VERSION_CODES.CUR_DEVELOPMENT; - } - return sdkVersion; + return Build.VERSION.SDK_INT; } @UsedForTesting diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 702efb3d7..1ef53a65d 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -46,6 +46,7 @@ import com.android.inputmethod.keyboard.internal.GestureTrailsDrawingPreview; import com.android.inputmethod.keyboard.internal.KeyDrawParams; import com.android.inputmethod.keyboard.internal.KeyPreviewChoreographer; import com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams; +import com.android.inputmethod.keyboard.internal.KeyPreviewView; import com.android.inputmethod.keyboard.internal.LanguageOnSpacebarHelper; import com.android.inputmethod.keyboard.internal.MoreKeySpec; import com.android.inputmethod.keyboard.internal.NonDistinctMultitouchHelper; @@ -764,6 +765,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack public void startDisplayLanguageOnSpacebar(final boolean subtypeChanged, final int languageOnSpacebarFormatType, final boolean hasMultipleEnabledIMEsOrSubtypes) { + if (subtypeChanged) { + KeyPreviewView.clearTextCache(); + } mLanguageOnSpacebarFormatType = languageOnSpacebarFormatType; mHasMultipleEnabledIMEsOrSubtypes = hasMultipleEnabledIMEsOrSubtypes; final ObjectAnimator animator = mLanguageOnSpacebarFadeoutAnimator; diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java index 360faf829..24538605a 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java @@ -17,7 +17,10 @@ package com.android.inputmethod.keyboard.internal; import android.content.Context; +import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.text.TextPaint; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; @@ -26,6 +29,8 @@ import android.widget.TextView; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.latin.R; +import java.util.HashSet; + /** * The pop up key preview view. */ @@ -34,6 +39,9 @@ public class KeyPreviewView extends TextView { public static final int POSITION_LEFT = 1; public static final int POSITION_RIGHT = 2; + private final Rect mBackgroundPadding = new Rect(); + private static final HashSet<String> sNoScaleXTextSet = new HashSet<>(); + public KeyPreviewView(final Context context, final AttributeSet attrs) { this(context, attrs, 0); } @@ -58,7 +66,48 @@ public class KeyPreviewView extends TextView { setTextSize(TypedValue.COMPLEX_UNIT_PX, key.selectPreviewTextSize(drawParams)); setTypeface(key.selectPreviewTypeface(drawParams)); // TODO Should take care of temporaryShiftLabel here. - setText(key.getPreviewLabel()); + setTextAndScaleX(key.getPreviewLabel()); + } + + private void setTextAndScaleX(final String text) { + setTextScaleX(1.0f); + setText(text); + if (sNoScaleXTextSet.contains(text)) { + return; + } + // TODO: Override {@link #setBackground(Drawable)} that is supported from API 16 and + // calculate maximum text width. + final Drawable background = getBackground(); + if (background == null) { + return; + } + background.getPadding(mBackgroundPadding); + final int maxWidth = background.getIntrinsicWidth() - mBackgroundPadding.left + - mBackgroundPadding.right; + final float width = getTextWidth(text, getPaint()); + if (width <= maxWidth) { + sNoScaleXTextSet.add(text); + return; + } + setTextScaleX(maxWidth / width); + } + + public static void clearTextCache() { + sNoScaleXTextSet.clear(); + } + + private static float getTextWidth(final String text, final TextPaint paint) { + if (TextUtils.isEmpty(text)) { + return 0.0f; + } + final int len = text.length(); + final float[] widths = new float[len]; + final int count = paint.getTextWidths(text, 0, len, widths); + float width = 0; + for (int i = 0; i < count; i++) { + width += widths[i]; + } + return width; } // Background state set diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 2e3cd6b6f..9b629ca14 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -145,6 +145,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // If it turns out we need several, it will get grown seamlessly. final SparseArray<HardwareEventDecoder> mHardwareEventDecoders = new SparseArray<>(1); + // TODO: Move these {@link View}s to {@link KeyboardSwitcher}. + private View mInputView; private View mExtractArea; private View mKeyPreviewBackingView; private SuggestionStripView mSuggestionStripView; @@ -153,6 +155,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; private final SubtypeSwitcher mSubtypeSwitcher; private final SubtypeState mSubtypeState = new SubtypeState(); + private final SpecialKeyDetector mSpecialKeyDetector = new SpecialKeyDetector(); // Object for reacting to adding/removing a dictionary pack. private final BroadcastReceiver mDictionaryPackInstallReceiver = @@ -709,6 +712,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void setInputView(final View view) { super.setInputView(view); + mInputView = view; mExtractArea = getWindow().getWindow().getDecorView() .findViewById(android.R.id.extractArea); mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing); @@ -1079,6 +1083,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (visibleKeyboardView == null || !hasSuggestionStripView()) { return; } + final boolean hasHardwareKeyboard = mKeyboardSwitcher.hasHardwareKeyboard(); + if (hasHardwareKeyboard && visibleKeyboardView.getVisibility() == View.GONE) { + // If there is a hardware keyboard and a visible software keyboard view has been hidden, + // no visual element will be shown on the screen. + outInsets.touchableInsets = mInputView.getHeight(); + outInsets.visibleTopInsets = mInputView.getHeight(); + return; + } final int adjustedBackingHeight = getAdjustedBackingViewHeight(); final boolean backingGone = (mKeyPreviewBackingView.getVisibility() == View.GONE); final int backingHeight = backingGone ? 0 : adjustedBackingHeight; @@ -1111,7 +1123,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } @Override + public boolean onEvaluateInputViewShown() { + // Always show {@link InputView}. + return true; + } + + @Override public boolean onEvaluateFullscreenMode() { + if (mKeyboardSwitcher.hasHardwareKeyboard()) { + // If there is a hardware keyboard, disable full screen mode. + return false; + } // Reread resource value here, because this method is called by the framework as needed. final boolean isFullscreenModeAllowed = Settings.readUseFullscreenMode(getResources()); if (super.onEvaluateFullscreenMode() && isFullscreenModeAllowed) { @@ -1568,6 +1590,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Hooks for hardware keyboard @Override public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) { + mSpecialKeyDetector.onKeyDown(keyEvent); if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) { return super.onKeyDown(keyCode, keyEvent); } @@ -1587,12 +1610,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } @Override - public boolean onKeyUp(final int keyCode, final KeyEvent event) { - final long keyIdentifier = event.getDeviceId() << 32 + event.getKeyCode(); + public boolean onKeyUp(final int keyCode, final KeyEvent keyEvent) { + mSpecialKeyDetector.onKeyUp(keyEvent); + if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) { + return super.onKeyUp(keyCode, keyEvent); + } + final long keyIdentifier = keyEvent.getDeviceId() << 32 + keyEvent.getKeyCode(); if (mInputLogic.mCurrentlyPressedHardwareKeys.remove(keyIdentifier)) { return true; } - return super.onKeyUp(keyCode, event); + return super.onKeyUp(keyCode, keyEvent); } // onKeyDown and onKeyUp are the main events we are interested in. There are two more events diff --git a/java/src/com/android/inputmethod/latin/SpecialKeyDetector.java b/java/src/com/android/inputmethod/latin/SpecialKeyDetector.java new file mode 100644 index 000000000..9d6c69ae7 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/SpecialKeyDetector.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014, 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.latin; + +import android.view.KeyEvent; + +final class SpecialKeyDetector { + /** + * Record a down key event. + * @param keyEvent a down key event. + */ + public void onKeyDown(final KeyEvent keyEvent) { + } + + /** + * Record an up key event. + * @param keyEvent an up key event. + */ + public void onKeyUp(final KeyEvent keyEvent) { + } +} |