Move key preview related methods to KeyPreviewChoreographer
Change-Id: Ia8d6b7fa922a4da233bf851b2e94bbd2573a65a3main
parent
f2749e41e4
commit
bb476be4e6
|
@ -16,10 +16,7 @@
|
|||
|
||||
package com.android.inputmethod.keyboard;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorInflater;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
@ -35,13 +32,10 @@ import android.preference.PreferenceManager;
|
|||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.inputmethod.InputMethodSubtype;
|
||||
import android.widget.TextView;
|
||||
|
||||
|
@ -53,6 +47,7 @@ import com.android.inputmethod.keyboard.internal.DrawingPreviewPlacerView;
|
|||
import com.android.inputmethod.keyboard.internal.GestureFloatingTextDrawingPreview;
|
||||
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.NonDistinctMultitouchHelper;
|
||||
import com.android.inputmethod.keyboard.internal.SlidingKeyInputDrawingPreview;
|
||||
|
@ -71,9 +66,6 @@ import com.android.inputmethod.latin.utils.UsabilityStudyLogUtils;
|
|||
import com.android.inputmethod.latin.utils.ViewLayoutUtils;
|
||||
import com.android.inputmethod.research.ResearchLogger;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
|
@ -161,18 +153,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
|
|||
|
||||
// Key preview
|
||||
private static final boolean FADE_OUT_KEY_TOP_LETTER_WHEN_KEY_IS_PRESSED = false;
|
||||
// Free {@link TextView} pool that can be used for key preview.
|
||||
private final ArrayDeque<TextView> mFreeKeyPreviewTextViews = CollectionUtils.newArrayDeque();
|
||||
// Map from {@link Key} to {@link TextView} that is currently being displayed as key preview.
|
||||
private final HashMap<Key,TextView> mShowingKeyPreviewTextViews = CollectionUtils.newHashMap();
|
||||
private final KeyPreviewDrawParams mKeyPreviewDrawParams;
|
||||
private static final float KEY_PREVIEW_START_ZOOM_IN_SCALE = 0.7f;
|
||||
private static final float KEY_PREVIEW_END_ZOOM_IN_SCALE = 1.0f;
|
||||
private static final float KEY_PREVIEW_END_ZOOM_OUT_SCALE = 0.7f;
|
||||
private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR =
|
||||
new AccelerateInterpolator();
|
||||
private static final DecelerateInterpolator DECELERATE_INTERPOLATOR =
|
||||
new DecelerateInterpolator();
|
||||
private final KeyPreviewChoreographer mKeyPreviewChoreographer;
|
||||
|
||||
// More keys keyboard
|
||||
private final Paint mBackgroundDimAlphaPaint = new Paint();
|
||||
|
@ -261,6 +243,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
|
|||
R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0);
|
||||
|
||||
mKeyPreviewDrawParams = new KeyPreviewDrawParams(mainKeyboardViewAttr);
|
||||
mKeyPreviewChoreographer = new KeyPreviewChoreographer(mKeyPreviewDrawParams);
|
||||
|
||||
final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId(
|
||||
R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0);
|
||||
mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean(
|
||||
|
@ -477,60 +461,13 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
|
|||
return mKeyPreviewDrawParams.isPopupEnabled();
|
||||
}
|
||||
|
||||
private TextView getKeyPreviewTextView(final Key key) {
|
||||
TextView previewTextView = mShowingKeyPreviewTextViews.remove(key);
|
||||
if (previewTextView != null) {
|
||||
return previewTextView;
|
||||
}
|
||||
previewTextView = mFreeKeyPreviewTextViews.poll();
|
||||
if (previewTextView != null) {
|
||||
return previewTextView;
|
||||
}
|
||||
final Context context = getContext();
|
||||
final int previewLayoutId = mKeyPreviewDrawParams.mLayoutId;
|
||||
if (previewLayoutId != 0) {
|
||||
previewTextView = (TextView)LayoutInflater.from(context)
|
||||
.inflate(previewLayoutId, null);
|
||||
} else {
|
||||
previewTextView = new TextView(context);
|
||||
}
|
||||
locatePreviewPlacerView();
|
||||
mDrawingPreviewPlacerView.addView(
|
||||
previewTextView, ViewLayoutUtils.newLayoutParam(mDrawingPreviewPlacerView, 0, 0));
|
||||
return previewTextView;
|
||||
}
|
||||
|
||||
// Implements {@link DrawingHandler.Callbacks} method.
|
||||
@Override
|
||||
public void dismissAllKeyPreviews() {
|
||||
for (final Key key : new HashSet<Key>(mShowingKeyPreviewTextViews.keySet())) {
|
||||
dismissKeyPreviewWithoutDelay(key);
|
||||
}
|
||||
mKeyPreviewChoreographer.dismissAllKeyPreviews();
|
||||
PointerTracker.setReleasedKeyGraphicsToAllKeys();
|
||||
}
|
||||
|
||||
// Background state set
|
||||
private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = {
|
||||
{ // STATE_MIDDLE
|
||||
EMPTY_STATE_SET,
|
||||
{ R.attr.state_has_morekeys }
|
||||
},
|
||||
{ // STATE_LEFT
|
||||
{ R.attr.state_left_edge },
|
||||
{ R.attr.state_left_edge, R.attr.state_has_morekeys }
|
||||
},
|
||||
{ // STATE_RIGHT
|
||||
{ R.attr.state_right_edge },
|
||||
{ R.attr.state_right_edge, R.attr.state_has_morekeys }
|
||||
}
|
||||
};
|
||||
private static final int STATE_MIDDLE = 0;
|
||||
private static final int STATE_LEFT = 1;
|
||||
private static final int STATE_RIGHT = 2;
|
||||
private static final int STATE_NORMAL = 0;
|
||||
private static final int STATE_HAS_MOREKEYS = 1;
|
||||
|
||||
// TODO: Take this method out of this class.
|
||||
@Override
|
||||
public void showKeyPreview(final Key key) {
|
||||
// If key is invalid or IME is already closed, we must not show key preview.
|
||||
|
@ -547,185 +484,31 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
|
|||
return;
|
||||
}
|
||||
|
||||
final TextView previewTextView = getKeyPreviewTextView(key);
|
||||
final KeyDrawParams drawParams = mKeyDrawParams;
|
||||
previewTextView.setTextColor(drawParams.mPreviewTextColor);
|
||||
final Drawable background = previewTextView.getBackground();
|
||||
final String label = key.getPreviewLabel();
|
||||
// What we show as preview should match what we show on a key top in onDraw().
|
||||
if (label != null) {
|
||||
// TODO Should take care of temporaryShiftLabel here.
|
||||
previewTextView.setCompoundDrawables(null, null, null, null);
|
||||
previewTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
|
||||
key.selectPreviewTextSize(drawParams));
|
||||
previewTextView.setTypeface(key.selectPreviewTypeface(drawParams));
|
||||
previewTextView.setText(label);
|
||||
} else {
|
||||
previewTextView.setCompoundDrawables(null, null, null,
|
||||
key.getPreviewIcon(keyboard.mIconsSet));
|
||||
previewTextView.setText(null);
|
||||
}
|
||||
|
||||
previewTextView.measure(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
final int keyDrawWidth = key.getDrawWidth();
|
||||
final int previewWidth = previewTextView.getMeasuredWidth();
|
||||
final int previewHeight = previewParams.mPreviewHeight;
|
||||
previewParams.setGeometry(previewTextView);
|
||||
locatePreviewPlacerView();
|
||||
final TextView previewTextView = mKeyPreviewChoreographer.getKeyPreviewTextView(
|
||||
key, mDrawingPreviewPlacerView);
|
||||
getLocationInWindow(mOriginCoords);
|
||||
// The key preview is horizontally aligned with the center of the visible part of the
|
||||
// parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and
|
||||
// the left/right background is used if such background is specified.
|
||||
final int statePosition;
|
||||
int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2
|
||||
+ CoordinateUtils.x(mOriginCoords);
|
||||
if (previewX < 0) {
|
||||
previewX = 0;
|
||||
statePosition = STATE_LEFT;
|
||||
} else if (previewX > getWidth() - previewWidth) {
|
||||
previewX = getWidth() - previewWidth;
|
||||
statePosition = STATE_RIGHT;
|
||||
} else {
|
||||
statePosition = STATE_MIDDLE;
|
||||
}
|
||||
// The key preview is placed vertically above the top edge of the parent key with an
|
||||
// arbitrary offset.
|
||||
final int previewY = key.getY() - previewHeight + previewParams.mPreviewOffset
|
||||
+ CoordinateUtils.y(mOriginCoords);
|
||||
|
||||
if (background != null) {
|
||||
final int hasMoreKeys = (key.getMoreKeys() != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL;
|
||||
background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[statePosition][hasMoreKeys]);
|
||||
}
|
||||
ViewLayoutUtils.placeViewAt(
|
||||
previewTextView, previewX, previewY, previewWidth, previewHeight);
|
||||
|
||||
if (!isHardwareAccelerated()) {
|
||||
previewTextView.setVisibility(VISIBLE);
|
||||
mShowingKeyPreviewTextViews.put(key, previewTextView);
|
||||
return;
|
||||
}
|
||||
previewTextView.setPivotX(previewWidth / 2.0f);
|
||||
previewTextView.setPivotY(previewHeight);
|
||||
|
||||
final Animator zoomIn = createZoomInAniation(key, previewTextView);
|
||||
final Animator zoomOut = createZoomOutAnimation(key, previewTextView);
|
||||
final KeyPreviewAnimations animation = new KeyPreviewAnimations(zoomIn, zoomOut);
|
||||
previewTextView.setTag(animation);
|
||||
animation.startZoomIn();
|
||||
}
|
||||
|
||||
// TODO: Move this internal class out to a separate external class.
|
||||
private static class KeyPreviewAnimations extends AnimatorListenerAdapter {
|
||||
private final Animator mZoomIn;
|
||||
private final Animator mZoomOut;
|
||||
|
||||
public KeyPreviewAnimations(final Animator zoomIn, final Animator zoomOut) {
|
||||
mZoomIn = zoomIn;
|
||||
mZoomOut = zoomOut;
|
||||
}
|
||||
|
||||
public void startZoomIn() {
|
||||
mZoomIn.start();
|
||||
}
|
||||
|
||||
public void startZoomOut() {
|
||||
if (mZoomIn.isRunning()) {
|
||||
mZoomIn.addListener(this);
|
||||
return;
|
||||
}
|
||||
mZoomOut.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(final Animator animation) {
|
||||
mZoomOut.start();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Take this method out of this class.
|
||||
private Animator createZoomInAniation(final Key key, final TextView previewTextView) {
|
||||
final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat(
|
||||
previewTextView, SCALE_X, KEY_PREVIEW_START_ZOOM_IN_SCALE,
|
||||
KEY_PREVIEW_END_ZOOM_IN_SCALE);
|
||||
final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat(
|
||||
previewTextView, SCALE_Y, KEY_PREVIEW_START_ZOOM_IN_SCALE,
|
||||
KEY_PREVIEW_END_ZOOM_IN_SCALE);
|
||||
final AnimatorSet zoomInAnimation = new AnimatorSet();
|
||||
zoomInAnimation.play(scaleXAnimation).with(scaleYAnimation);
|
||||
// TODO: Implement preference option to control key preview animation duration.
|
||||
zoomInAnimation.setDuration(mKeyPreviewDrawParams.mZoomInDuration);
|
||||
zoomInAnimation.setInterpolator(DECELERATE_INTERPOLATOR);
|
||||
zoomInAnimation.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(final Animator animation) {
|
||||
previewTextView.setVisibility(VISIBLE);
|
||||
mShowingKeyPreviewTextViews.put(key, previewTextView);
|
||||
}
|
||||
});
|
||||
return zoomInAnimation;
|
||||
}
|
||||
|
||||
// TODO: Take this method out of this class.
|
||||
private Animator createZoomOutAnimation(final Key key, final TextView previewTextView) {
|
||||
final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat(
|
||||
previewTextView, SCALE_X, KEY_PREVIEW_END_ZOOM_OUT_SCALE);
|
||||
final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat(
|
||||
previewTextView, SCALE_Y, KEY_PREVIEW_END_ZOOM_OUT_SCALE);
|
||||
final AnimatorSet zoomOutAnimation = new AnimatorSet();
|
||||
zoomOutAnimation.play(scaleXAnimation).with(scaleYAnimation);
|
||||
// TODO: Implement preference option to control key preview animation duration.
|
||||
final int zoomOutDuration = Math.min(mKeyPreviewDrawParams.mZoomOutDuration,
|
||||
mKeyPreviewDrawParams.getLingerTimeout());
|
||||
zoomOutAnimation.setDuration(zoomOutDuration);
|
||||
zoomOutAnimation.setInterpolator(ACCELERATE_INTERPOLATOR);
|
||||
zoomOutAnimation.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(final Animator animation) {
|
||||
dismissKeyPreviewWithoutDelay(key);
|
||||
}
|
||||
});
|
||||
return zoomOutAnimation;
|
||||
mKeyPreviewChoreographer.placeKeyPreview(key, previewTextView, keyboard.mIconsSet,
|
||||
mKeyDrawParams, getWidth(), mOriginCoords);
|
||||
mKeyPreviewChoreographer.showKeyPreview(key, previewTextView, isHardwareAccelerated());
|
||||
}
|
||||
|
||||
// Implements {@link TimerHandler.Callbacks} method.
|
||||
// TODO: Take this method out of this class.
|
||||
@Override
|
||||
public void dismissKeyPreviewWithoutDelay(final Key key) {
|
||||
if (key == null) {
|
||||
return;
|
||||
}
|
||||
final TextView previewTextView = mShowingKeyPreviewTextViews.remove(key);
|
||||
if (previewTextView != null) {
|
||||
final Object tag = previewTextView.getTag();
|
||||
if (tag instanceof Animator) {
|
||||
((Animator)tag).cancel();
|
||||
}
|
||||
previewTextView.setTag(null);
|
||||
previewTextView.setVisibility(INVISIBLE);
|
||||
mFreeKeyPreviewTextViews.add(previewTextView);
|
||||
}
|
||||
mKeyPreviewChoreographer.dismissKeyPreview(key, false /* withAnimation */);
|
||||
// To redraw key top letter.
|
||||
invalidateKey(key);
|
||||
}
|
||||
|
||||
// TODO: Take this method out of this class.
|
||||
@Override
|
||||
public void dismissKeyPreview(final Key key) {
|
||||
final TextView previewTextView = mShowingKeyPreviewTextViews.get(key);
|
||||
if (previewTextView == null) {
|
||||
return;
|
||||
}
|
||||
if (!isHardwareAccelerated()) {
|
||||
// TODO: Implement preference option to control key preview method and duration.
|
||||
mDrawingHandler.dismissKeyPreview(mKeyPreviewDrawParams.getLingerTimeout(), key);
|
||||
return;
|
||||
}
|
||||
final Object tag = previewTextView.getTag();
|
||||
if (tag instanceof KeyPreviewAnimations) {
|
||||
final KeyPreviewAnimations animation = (KeyPreviewAnimations)tag;
|
||||
animation.startZoomOut();
|
||||
}
|
||||
mKeyPreviewChoreographer.dismissKeyPreview(key, true /* withAnimation */);
|
||||
}
|
||||
|
||||
public void setSlidingKeyInputPreviewEnabled(final boolean enabled) {
|
||||
|
@ -1098,7 +881,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
|
|||
}
|
||||
// Don't draw key top letter when key preview is showing.
|
||||
if (FADE_OUT_KEY_TOP_LETTER_WHEN_KEY_IS_PRESSED
|
||||
&& mShowingKeyPreviewTextViews.containsKey(key)) {
|
||||
&& mKeyPreviewChoreographer.isShowingKeyPreview(key)) {
|
||||
// TODO: Fade out animation for the key top letter, and fade in animation for the key
|
||||
// background color when the user presses the key.
|
||||
return;
|
||||
|
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* 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.keyboard.internal;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.inputmethod.keyboard.Key;
|
||||
import com.android.inputmethod.latin.R;
|
||||
import com.android.inputmethod.latin.utils.CollectionUtils;
|
||||
import com.android.inputmethod.latin.utils.CoordinateUtils;
|
||||
import com.android.inputmethod.latin.utils.ViewLayoutUtils;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* This class controls pop up key previews. This class decides:
|
||||
* - what kind of key previews should be shown.
|
||||
* - where key previews should be placed.
|
||||
* - how key previews should be shown and dismissed.
|
||||
*/
|
||||
public final class KeyPreviewChoreographer {
|
||||
// Free {@link TextView} pool that can be used for key preview.
|
||||
private final ArrayDeque<TextView> mFreeKeyPreviewTextViews = CollectionUtils.newArrayDeque();
|
||||
// Map from {@link Key} to {@link TextView} that is currently being displayed as key preview.
|
||||
private final HashMap<Key,TextView> mShowingKeyPreviewTextViews = CollectionUtils.newHashMap();
|
||||
|
||||
private final KeyPreviewDrawParams mParams;
|
||||
|
||||
public KeyPreviewChoreographer(final KeyPreviewDrawParams params) {
|
||||
mParams = params;
|
||||
}
|
||||
|
||||
public TextView getKeyPreviewTextView(final Key key, final ViewGroup placerView) {
|
||||
TextView previewTextView = mShowingKeyPreviewTextViews.remove(key);
|
||||
if (previewTextView != null) {
|
||||
return previewTextView;
|
||||
}
|
||||
previewTextView = mFreeKeyPreviewTextViews.poll();
|
||||
if (previewTextView != null) {
|
||||
return previewTextView;
|
||||
}
|
||||
final Context context = placerView.getContext();
|
||||
if (mParams.mLayoutId != 0) {
|
||||
previewTextView = (TextView)LayoutInflater.from(context)
|
||||
.inflate(mParams.mLayoutId, null);
|
||||
} else {
|
||||
previewTextView = new TextView(context);
|
||||
}
|
||||
placerView.addView(previewTextView, ViewLayoutUtils.newLayoutParam(placerView, 0, 0));
|
||||
return previewTextView;
|
||||
}
|
||||
|
||||
public boolean isShowingKeyPreview(final Key key) {
|
||||
return mShowingKeyPreviewTextViews.containsKey(key);
|
||||
}
|
||||
|
||||
public void dismissAllKeyPreviews() {
|
||||
for (final Key key : new HashSet<Key>(mShowingKeyPreviewTextViews.keySet())) {
|
||||
dismissKeyPreview(key, false /* withAnimation */);
|
||||
}
|
||||
}
|
||||
|
||||
public void dismissKeyPreview(final Key key, final boolean withAnimation) {
|
||||
if (key == null) {
|
||||
return;
|
||||
}
|
||||
final TextView previewTextView = mShowingKeyPreviewTextViews.get(key);
|
||||
if (previewTextView == null) {
|
||||
return;
|
||||
}
|
||||
final Object tag = previewTextView.getTag();
|
||||
if (withAnimation) {
|
||||
if (tag instanceof KeyPreviewAnimations) {
|
||||
final KeyPreviewAnimations animation = (KeyPreviewAnimations)tag;
|
||||
animation.startZoomOut();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Dismiss preview without animation.
|
||||
if (tag instanceof Animator) {
|
||||
((Animator)tag).cancel();
|
||||
}
|
||||
previewTextView.setTag(null);
|
||||
previewTextView.setVisibility(View.INVISIBLE);
|
||||
mFreeKeyPreviewTextViews.add(previewTextView);
|
||||
}
|
||||
|
||||
// Background state set
|
||||
private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = {
|
||||
{ // STATE_MIDDLE
|
||||
{},
|
||||
{ R.attr.state_has_morekeys }
|
||||
},
|
||||
{ // STATE_LEFT
|
||||
{ R.attr.state_left_edge },
|
||||
{ R.attr.state_left_edge, R.attr.state_has_morekeys }
|
||||
},
|
||||
{ // STATE_RIGHT
|
||||
{ R.attr.state_right_edge },
|
||||
{ R.attr.state_right_edge, R.attr.state_has_morekeys }
|
||||
}
|
||||
};
|
||||
private static final int STATE_MIDDLE = 0;
|
||||
private static final int STATE_LEFT = 1;
|
||||
private static final int STATE_RIGHT = 2;
|
||||
private static final int STATE_NORMAL = 0;
|
||||
private static final int STATE_HAS_MOREKEYS = 1;
|
||||
|
||||
public void placeKeyPreview(final Key key, final TextView previewTextView,
|
||||
final KeyboardIconsSet iconsSet, final KeyDrawParams drawParams,
|
||||
final int keyboardViewWidth, final int[] originCoords) {
|
||||
previewTextView.setTextColor(drawParams.mPreviewTextColor);
|
||||
final Drawable background = previewTextView.getBackground();
|
||||
final String label = key.getPreviewLabel();
|
||||
// What we show as preview should match what we show on a key top in onDraw().
|
||||
if (label != null) {
|
||||
// TODO Should take care of temporaryShiftLabel here.
|
||||
previewTextView.setCompoundDrawables(null, null, null, null);
|
||||
previewTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
|
||||
key.selectPreviewTextSize(drawParams));
|
||||
previewTextView.setTypeface(key.selectPreviewTypeface(drawParams));
|
||||
previewTextView.setText(label);
|
||||
} else {
|
||||
previewTextView.setCompoundDrawables(null, null, null, key.getPreviewIcon(iconsSet));
|
||||
previewTextView.setText(null);
|
||||
}
|
||||
|
||||
previewTextView.measure(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
mParams.setGeometry(previewTextView);
|
||||
final int previewWidth = previewTextView.getMeasuredWidth();
|
||||
final int previewHeight = mParams.mPreviewHeight;
|
||||
final int keyDrawWidth = key.getDrawWidth();
|
||||
// The key preview is horizontally aligned with the center of the visible part of the
|
||||
// parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and
|
||||
// the left/right background is used if such background is specified.
|
||||
final int statePosition;
|
||||
int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2
|
||||
+ CoordinateUtils.x(originCoords);
|
||||
if (previewX < 0) {
|
||||
previewX = 0;
|
||||
statePosition = STATE_LEFT;
|
||||
} else if (previewX > keyboardViewWidth - previewWidth) {
|
||||
previewX = keyboardViewWidth - previewWidth;
|
||||
statePosition = STATE_RIGHT;
|
||||
} else {
|
||||
statePosition = STATE_MIDDLE;
|
||||
}
|
||||
// The key preview is placed vertically above the top edge of the parent key with an
|
||||
// arbitrary offset.
|
||||
final int previewY = key.getY() - previewHeight + mParams.mPreviewOffset
|
||||
+ CoordinateUtils.y(originCoords);
|
||||
|
||||
if (background != null) {
|
||||
final int hasMoreKeys = (key.getMoreKeys() != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL;
|
||||
background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[statePosition][hasMoreKeys]);
|
||||
}
|
||||
ViewLayoutUtils.placeViewAt(
|
||||
previewTextView, previewX, previewY, previewWidth, previewHeight);
|
||||
previewTextView.setPivotX(previewWidth / 2.0f);
|
||||
previewTextView.setPivotY(previewHeight);
|
||||
}
|
||||
|
||||
public void showKeyPreview(final Key key, final TextView previewTextView,
|
||||
final boolean withAnimation) {
|
||||
if (!withAnimation) {
|
||||
previewTextView.setVisibility(View.VISIBLE);
|
||||
mShowingKeyPreviewTextViews.put(key, previewTextView);
|
||||
return;
|
||||
}
|
||||
|
||||
// Show preview with animation.
|
||||
final Animator zoomIn = createZoomInAniation(key, previewTextView);
|
||||
final Animator zoomOut = createZoomOutAnimation(key, previewTextView);
|
||||
final KeyPreviewAnimations animation = new KeyPreviewAnimations(zoomIn, zoomOut);
|
||||
previewTextView.setTag(animation);
|
||||
animation.startZoomIn();
|
||||
}
|
||||
|
||||
// TODO: Move these parameters to resources or preferences.
|
||||
private static final float KEY_PREVIEW_START_ZOOM_IN_SCALE = 0.7f;
|
||||
private static final float KEY_PREVIEW_END_ZOOM_IN_SCALE = 1.0f;
|
||||
private static final float KEY_PREVIEW_END_ZOOM_OUT_SCALE = 0.7f;
|
||||
private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR =
|
||||
new AccelerateInterpolator();
|
||||
private static final DecelerateInterpolator DECELERATE_INTERPOLATOR =
|
||||
new DecelerateInterpolator();
|
||||
|
||||
private Animator createZoomInAniation(final Key key, final TextView previewTextView) {
|
||||
final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat(
|
||||
previewTextView, View.SCALE_X, KEY_PREVIEW_START_ZOOM_IN_SCALE,
|
||||
KEY_PREVIEW_END_ZOOM_IN_SCALE);
|
||||
final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat(
|
||||
previewTextView, View.SCALE_Y, KEY_PREVIEW_START_ZOOM_IN_SCALE,
|
||||
KEY_PREVIEW_END_ZOOM_IN_SCALE);
|
||||
final AnimatorSet zoomInAnimation = new AnimatorSet();
|
||||
zoomInAnimation.play(scaleXAnimation).with(scaleYAnimation);
|
||||
// TODO: Implement preference option to control key preview animation duration.
|
||||
zoomInAnimation.setDuration(mParams.mZoomInDuration);
|
||||
zoomInAnimation.setInterpolator(DECELERATE_INTERPOLATOR);
|
||||
zoomInAnimation.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(final Animator animation) {
|
||||
showKeyPreview(key, previewTextView, false /* withAnimation */);
|
||||
}
|
||||
});
|
||||
return zoomInAnimation;
|
||||
}
|
||||
|
||||
private Animator createZoomOutAnimation(final Key key, final TextView previewTextView) {
|
||||
final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat(
|
||||
previewTextView, View.SCALE_X, KEY_PREVIEW_END_ZOOM_OUT_SCALE);
|
||||
final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat(
|
||||
previewTextView, View.SCALE_Y, KEY_PREVIEW_END_ZOOM_OUT_SCALE);
|
||||
final AnimatorSet zoomOutAnimation = new AnimatorSet();
|
||||
zoomOutAnimation.play(scaleXAnimation).with(scaleYAnimation);
|
||||
// TODO: Implement preference option to control key preview animation duration.
|
||||
final int zoomOutDuration = Math.min(mParams.mZoomOutDuration, mParams.getLingerTimeout());
|
||||
zoomOutAnimation.setDuration(zoomOutDuration);
|
||||
zoomOutAnimation.setInterpolator(ACCELERATE_INTERPOLATOR);
|
||||
zoomOutAnimation.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(final Animator animation) {
|
||||
dismissKeyPreview(key, false /* withAnimation */);
|
||||
}
|
||||
});
|
||||
return zoomOutAnimation;
|
||||
}
|
||||
|
||||
private static class KeyPreviewAnimations extends AnimatorListenerAdapter {
|
||||
private final Animator mZoomIn;
|
||||
private final Animator mZoomOut;
|
||||
|
||||
public KeyPreviewAnimations(final Animator zoomIn, final Animator zoomOut) {
|
||||
mZoomIn = zoomIn;
|
||||
mZoomOut = zoomOut;
|
||||
}
|
||||
|
||||
public void startZoomIn() {
|
||||
mZoomIn.start();
|
||||
}
|
||||
|
||||
public void startZoomOut() {
|
||||
if (mZoomIn.isRunning()) {
|
||||
mZoomIn.addListener(this);
|
||||
return;
|
||||
}
|
||||
mZoomOut.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(final Animator animation) {
|
||||
mZoomOut.start();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ public final class KeyPreviewDrawParams {
|
|||
public final int mLayoutId;
|
||||
public final int mPreviewOffset;
|
||||
public final int mPreviewHeight;
|
||||
// TODO: Move those parameters to preferences.
|
||||
public final int mZoomInDuration;
|
||||
public final int mZoomOutDuration;
|
||||
private int mLingerTimeout;
|
||||
|
|
Loading…
Reference in New Issue