Implement key preview zoom in/out animations

Bug: 11518021
Change-Id: I139b18708055e0811234886578c5a30b8cc71fec
main
Tadashi G. Takaoka 2013-11-18 19:20:32 +09:00
parent 7c542558bf
commit 585fa0491a
4 changed files with 153 additions and 19 deletions

View File

@ -109,6 +109,10 @@
<attr name="keyPreviewOffset" format="dimension" /> <attr name="keyPreviewOffset" format="dimension" />
<!-- Height of the key press feedback popup. --> <!-- Height of the key press feedback popup. -->
<attr name="keyPreviewHeight" format="dimension" /> <attr name="keyPreviewHeight" format="dimension" />
<!-- Duration of key preview popup zoom in animation in millisecond -->
<attr name="keyPreviewZoomInDuration" format="integer" />
<!-- Duration of key preview popup zoom out animation in millisecond -->
<attr name="keyPreviewZoomOutDuration" format="integer" />
<!-- Delay after key releasing and key press feedback dismissing in millisecond --> <!-- Delay after key releasing and key press feedback dismissing in millisecond -->
<attr name="keyPreviewLingerTimeout" format="integer" /> <attr name="keyPreviewLingerTimeout" format="integer" />
<!-- Layout resource for more keys keyboard --> <!-- Layout resource for more keys keyboard -->

View File

@ -52,6 +52,8 @@
<dimen name="config_key_hysteresis_distance_for_sliding_modifier">8.0dp</dimen> <dimen name="config_key_hysteresis_distance_for_sliding_modifier">8.0dp</dimen>
<integer name="config_touch_noise_threshold_time">40</integer> <integer name="config_touch_noise_threshold_time">40</integer>
<dimen name="config_touch_noise_threshold_distance">12.6dp</dimen> <dimen name="config_touch_noise_threshold_distance">12.6dp</dimen>
<integer name="config_key_preview_zoom_in_duration">35</integer>
<integer name="config_key_preview_zoom_out_duration">40</integer>
<integer name="config_key_preview_linger_timeout">70</integer> <integer name="config_key_preview_linger_timeout">70</integer>
<bool name="config_key_selection_by_dragging_finger">true</bool> <bool name="config_key_selection_by_dragging_finger">true</bool>
<!-- Sliding key input preview parameters --> <!-- Sliding key input preview parameters -->

View File

@ -77,6 +77,8 @@
<item name="ignoreAltCodeKeyTimeout">@integer/config_ignore_alt_code_key_timeout</item> <item name="ignoreAltCodeKeyTimeout">@integer/config_ignore_alt_code_key_timeout</item>
<item name="keyPreviewLayout">@layout/key_preview</item> <item name="keyPreviewLayout">@layout/key_preview</item>
<item name="keyPreviewHeight">@dimen/key_preview_height</item> <item name="keyPreviewHeight">@dimen/key_preview_height</item>
<item name="keyPreviewZoomInDuration">@integer/config_key_preview_zoom_in_duration</item>
<item name="keyPreviewZoomOutDuration">@integer/config_key_preview_zoom_out_duration</item>
<item name="keyPreviewLingerTimeout">@integer/config_key_preview_linger_timeout</item> <item name="keyPreviewLingerTimeout">@integer/config_key_preview_linger_timeout</item>
<item name="moreKeysKeyboardLayout">@layout/more_keys_keyboard</item> <item name="moreKeysKeyboardLayout">@layout/more_keys_keyboard</item>
<item name="showMoreKeysKeyboardAtTouchedPoint">@bool/config_show_more_keys_keyboard_at_touched_point</item> <item name="showMoreKeysKeyboardAtTouchedPoint">@bool/config_show_more_keys_keyboard_at_touched_point</item>

View File

@ -16,7 +16,10 @@
package com.android.inputmethod.keyboard; package com.android.inputmethod.keyboard;
import android.animation.Animator;
import android.animation.AnimatorInflater; import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator; import android.animation.ObjectAnimator;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -40,6 +43,8 @@ import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.inputmethod.InputMethodSubtype; import android.view.inputmethod.InputMethodSubtype;
import android.widget.TextView; import android.widget.TextView;
@ -168,6 +173,15 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private final KeyPreviewDrawParams mKeyPreviewDrawParams = new KeyPreviewDrawParams(); private final KeyPreviewDrawParams mKeyPreviewDrawParams = new KeyPreviewDrawParams();
private boolean mShowKeyPreviewPopup = true; private boolean mShowKeyPreviewPopup = true;
private int mKeyPreviewLingerTimeout; private int mKeyPreviewLingerTimeout;
private int mKeyPreviewZoomInDuration;
private int mKeyPreviewZoomOutDuration;
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();
// More keys keyboard // More keys keyboard
private final Paint mBackgroundDimAlphaPaint = new Paint(); private final Paint mBackgroundDimAlphaPaint = new Paint();
@ -389,17 +403,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
if (mainKeyboardView == null) return; if (mainKeyboardView == null) return;
switch (msg.what) { switch (msg.what) {
case MSG_DISMISS_KEY_PREVIEW: case MSG_DISMISS_KEY_PREVIEW:
final Key key = (Key)msg.obj; mainKeyboardView.dismissKeyPreviewWithoutDelay((Key)msg.obj);
if (key != null) {
final TextView previewTextView =
mainKeyboardView.mShowingKeyPreviewTextViews.remove(key);
if (previewTextView != null) {
previewTextView.setVisibility(INVISIBLE);
mainKeyboardView.mFreeKeyPreviewTextViews.add(previewTextView);
}
// To redraw key top letter.
mainKeyboardView.invalidateKey(key);
}
break; break;
case MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT: case MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT:
mainKeyboardView.showGestureFloatingPreviewText(SuggestedWords.EMPTY); mainKeyboardView.showGestureFloatingPreviewText(SuggestedWords.EMPTY);
@ -413,6 +417,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private void cancelAllDismissKeyPreviews() { private void cancelAllDismissKeyPreviews() {
removeMessages(MSG_DISMISS_KEY_PREVIEW); removeMessages(MSG_DISMISS_KEY_PREVIEW);
final MainKeyboardView mainKeyboardView = getOuterInstance();
if (mainKeyboardView == null) return;
mainKeyboardView.dismissAllKeyPreviews();
} }
public void dismissGestureFloatingPreviewText(final long delay) { public void dismissGestureFloatingPreviewText(final long delay) {
@ -487,6 +494,10 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
if (mKeyPreviewLayoutId == 0) { if (mKeyPreviewLayoutId == 0) {
mShowKeyPreviewPopup = false; mShowKeyPreviewPopup = false;
} }
mKeyPreviewZoomInDuration = mainKeyboardViewAttr.getInt(
R.styleable.MainKeyboardView_keyPreviewZoomInDuration, 0);
mKeyPreviewZoomOutDuration = mainKeyboardViewAttr.getInt(
R.styleable.MainKeyboardView_keyPreviewZoomOutDuration, 0);
final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId( final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId(
R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0); R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0);
mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean( mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean(
@ -712,11 +723,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private void dismissAllKeyPreviews() { private void dismissAllKeyPreviews() {
for (final Key key : new HashSet<Key>(mShowingKeyPreviewTextViews.keySet())) { for (final Key key : new HashSet<Key>(mShowingKeyPreviewTextViews.keySet())) {
final TextView previewTextView = mShowingKeyPreviewTextViews.remove(key); dismissKeyPreviewWithoutDelay(key);
if (previewTextView != null) {
previewTextView.setVisibility(INVISIBLE);
mFreeKeyPreviewTextViews.add(previewTextView);
}
} }
PointerTracker.setReleasedKeyGraphicsToAllKeys(); PointerTracker.setReleasedKeyGraphicsToAllKeys();
} }
@ -742,6 +749,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private static final int STATE_NORMAL = 0; private static final int STATE_NORMAL = 0;
private static final int STATE_HAS_MOREKEYS = 1; private static final int STATE_HAS_MOREKEYS = 1;
// TODO: Take this method out of this class.
@Override @Override
public void showKeyPreview(final Key key) { public void showKeyPreview(final Key key) {
// If key is invalid or IME is already closed, we must not show key preview. // If key is invalid or IME is already closed, we must not show key preview.
@ -819,13 +827,129 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
} }
ViewLayoutUtils.placeViewAt( ViewLayoutUtils.placeViewAt(
previewTextView, previewX, previewY, previewWidth, previewHeight); previewTextView, previewX, previewY, previewWidth, previewHeight);
previewTextView.setVisibility(VISIBLE);
mShowingKeyPreviewTextViews.put(key, previewTextView); 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(mKeyPreviewZoomInDuration);
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.
zoomOutAnimation.setDuration(mKeyPreviewZoomOutDuration);
zoomOutAnimation.setInterpolator(ACCELERATE_INTERPOLATOR);
zoomOutAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator animation) {
dismissKeyPreviewWithoutDelay(key);
}
});
return zoomOutAnimation;
}
// TODO: Take this method out of this class.
private 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);
}
// To redraw key top letter.
invalidateKey(key);
}
// TODO: Take this method out of this class.
@Override @Override
public void dismissKeyPreview(final Key key) { public void dismissKeyPreview(final Key key) {
mDrawingHandler.dismissKeyPreview(mKeyPreviewLingerTimeout, 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(mKeyPreviewLingerTimeout, key);
return;
}
final Object tag = previewTextView.getTag();
if (tag instanceof KeyPreviewAnimations) {
final KeyPreviewAnimations animation = (KeyPreviewAnimations)tag;
animation.startZoomOut();
}
} }
public void setSlidingKeyInputPreviewEnabled(final boolean enabled) { public void setSlidingKeyInputPreviewEnabled(final boolean enabled) {
@ -984,6 +1108,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
final int pointY = key.getY() + mKeyPreviewDrawParams.mPreviewVisibleOffset; final int pointY = key.getY() + mKeyPreviewDrawParams.mPreviewVisibleOffset;
moreKeysPanel.showMoreKeysPanel(this, this, pointX, pointY, mKeyboardActionListener); moreKeysPanel.showMoreKeysPanel(this, this, pointX, pointY, mKeyboardActionListener);
tracker.onShowMoreKeysPanel(moreKeysPanel); tracker.onShowMoreKeysPanel(moreKeysPanel);
// TODO: Implement zoom in animation of more keys panel.
dismissKeyPreviewWithoutDelay(key);
} }
public boolean isInDraggingFinger() { public boolean isInDraggingFinger() {