1bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka/*
2bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * Copyright (C) 2014 The Android Open Source Project
3bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka *
4bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
5bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * you may not use this file except in compliance with the License.
6bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * You may obtain a copy of the License at
7bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka *
8bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
9bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka *
10bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
11bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
12bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * See the License for the specific language governing permissions and
14bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * limitations under the License.
15bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka */
16bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
17bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokapackage com.android.inputmethod.keyboard.internal;
18bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
19bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokaimport android.animation.Animator;
20bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokaimport android.animation.AnimatorListenerAdapter;
21bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokaimport android.content.Context;
22bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokaimport android.view.View;
23bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokaimport android.view.ViewGroup;
24bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
25bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Key;
26bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.CoordinateUtils;
27bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.ViewLayoutUtils;
28bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
29bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokaimport java.util.ArrayDeque;
30bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokaimport java.util.HashMap;
31bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokaimport java.util.HashSet;
32bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
33bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka/**
34bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * This class controls pop up key previews. This class decides:
35bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * - what kind of key previews should be shown.
36bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * - where key previews should be placed.
37bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * - how key previews should be shown and dismissed.
38bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka */
39bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokapublic final class KeyPreviewChoreographer {
40615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    // Free {@link KeyPreviewView} pool that can be used for key preview.
41615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    private final ArrayDeque<KeyPreviewView> mFreeKeyPreviewViews = new ArrayDeque<>();
42615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    // Map from {@link Key} to {@link KeyPreviewView} that is currently being displayed as key
43615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    // preview.
44615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    private final HashMap<Key,KeyPreviewView> mShowingKeyPreviewViews = new HashMap<>();
45bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
46bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    private final KeyPreviewDrawParams mParams;
47bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
48bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    public KeyPreviewChoreographer(final KeyPreviewDrawParams params) {
49bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        mParams = params;
50bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
51bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
52615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    public KeyPreviewView getKeyPreviewView(final Key key, final ViewGroup placerView) {
53615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        KeyPreviewView keyPreviewView = mShowingKeyPreviewViews.remove(key);
54615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        if (keyPreviewView != null) {
55615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka            return keyPreviewView;
56bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
57615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView = mFreeKeyPreviewViews.poll();
58615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        if (keyPreviewView != null) {
59615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka            return keyPreviewView;
60bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
61bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        final Context context = placerView.getContext();
62615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView = new KeyPreviewView(context, null /* attrs */);
63615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.setBackgroundResource(mParams.mPreviewBackgroundResId);
64615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        placerView.addView(keyPreviewView, ViewLayoutUtils.newLayoutParam(placerView, 0, 0));
65615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        return keyPreviewView;
66bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
67bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
68bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    public boolean isShowingKeyPreview(final Key key) {
69615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        return mShowingKeyPreviewViews.containsKey(key);
70bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
71bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
72bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    public void dismissAllKeyPreviews() {
73615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        for (final Key key : new HashSet<>(mShowingKeyPreviewViews.keySet())) {
74bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            dismissKeyPreview(key, false /* withAnimation */);
75bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
76bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
77bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
78bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    public void dismissKeyPreview(final Key key, final boolean withAnimation) {
79bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        if (key == null) {
80bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            return;
81bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
82615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        final KeyPreviewView keyPreviewView = mShowingKeyPreviewViews.get(key);
83615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        if (keyPreviewView == null) {
84bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            return;
85bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
86615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        final Object tag = keyPreviewView.getTag();
87bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        if (withAnimation) {
88ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            if (tag instanceof KeyPreviewAnimators) {
89ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka                final KeyPreviewAnimators animators = (KeyPreviewAnimators)tag;
90ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka                animators.startDismiss();
917e9b0b42bfd5c51f4bc236a73df3f14cf583c989Tadashi G. Takaoka                return;
92bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            }
93bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
94bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        // Dismiss preview without animation.
95615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        mShowingKeyPreviewViews.remove(key);
96bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        if (tag instanceof Animator) {
97bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            ((Animator)tag).cancel();
98bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
99615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.setTag(null);
100615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.setVisibility(View.INVISIBLE);
101615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        mFreeKeyPreviewViews.add(keyPreviewView);
102bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
103bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
10484405d2a6815a99992849e821e073835f2d892e3Tadashi G. Takaoka    public void placeAndShowKeyPreview(final Key key, final KeyboardIconsSet iconsSet,
1053ff72dd0daa9baaeb4d6b8ade59d65c1f0e8b34fTadashi G. Takaoka            final KeyDrawParams drawParams, final int keyboardViewWidth, final int[] keyboardOrigin,
1063ff72dd0daa9baaeb4d6b8ade59d65c1f0e8b34fTadashi G. Takaoka            final ViewGroup placerView, final boolean withAnimation) {
107615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        final KeyPreviewView keyPreviewView = getKeyPreviewView(key, placerView);
1083ff72dd0daa9baaeb4d6b8ade59d65c1f0e8b34fTadashi G. Takaoka        placeKeyPreview(
109615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka                key, keyPreviewView, iconsSet, drawParams, keyboardViewWidth, keyboardOrigin);
110615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        showKeyPreview(key, keyPreviewView, withAnimation);
1113ff72dd0daa9baaeb4d6b8ade59d65c1f0e8b34fTadashi G. Takaoka    }
1123ff72dd0daa9baaeb4d6b8ade59d65c1f0e8b34fTadashi G. Takaoka
113615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    private void placeKeyPreview(final Key key, final KeyPreviewView keyPreviewView,
114bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            final KeyboardIconsSet iconsSet, final KeyDrawParams drawParams,
115bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            final int keyboardViewWidth, final int[] originCoords) {
116615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.setPreviewVisual(key, iconsSet, drawParams);
117615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.measure(
118bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
119615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        mParams.setGeometry(keyPreviewView);
120615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        final int previewWidth = keyPreviewView.getMeasuredWidth();
121bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        final int previewHeight = mParams.mPreviewHeight;
122bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        final int keyDrawWidth = key.getDrawWidth();
123bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        // The key preview is horizontally aligned with the center of the visible part of the
124bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        // parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and
125bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        // the left/right background is used if such background is specified.
126615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        final int keyPreviewPosition;
127bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2
128bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka                + CoordinateUtils.x(originCoords);
129bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        if (previewX < 0) {
130bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            previewX = 0;
131615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka            keyPreviewPosition = KeyPreviewView.POSITION_LEFT;
132bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        } else if (previewX > keyboardViewWidth - previewWidth) {
133bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            previewX = keyboardViewWidth - previewWidth;
134615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka            keyPreviewPosition = KeyPreviewView.POSITION_RIGHT;
135bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        } else {
136615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka            keyPreviewPosition = KeyPreviewView.POSITION_MIDDLE;
137bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
138615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        final boolean hasMoreKeys = (key.getMoreKeys() != null);
139615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.setPreviewBackground(hasMoreKeys, keyPreviewPosition);
140bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        // The key preview is placed vertically above the top edge of the parent key with an
141bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        // arbitrary offset.
142bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        final int previewY = key.getY() - previewHeight + mParams.mPreviewOffset
143bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka                + CoordinateUtils.y(originCoords);
144bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
145bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        ViewLayoutUtils.placeViewAt(
146615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka                keyPreviewView, previewX, previewY, previewWidth, previewHeight);
147615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.setPivotX(previewWidth / 2.0f);
148615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.setPivotY(previewHeight);
149bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
150bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
151615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    private void showKeyPreview(final Key key, final KeyPreviewView keyPreviewView,
152bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            final boolean withAnimation) {
153bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        if (!withAnimation) {
154615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka            keyPreviewView.setVisibility(View.VISIBLE);
155615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka            mShowingKeyPreviewViews.put(key, keyPreviewView);
156bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            return;
157bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
158bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
159bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        // Show preview with animation.
160ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        final Animator showUpAnimator = createShowUpAnimator(key, keyPreviewView);
161ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        final Animator dismissAnimator = createDismissAnimator(key, keyPreviewView);
162ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        final KeyPreviewAnimators animators = new KeyPreviewAnimators(
163ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka                showUpAnimator, dismissAnimator);
164ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        keyPreviewView.setTag(animators);
165ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        animators.startShowUp();
166bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
167bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
168ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka    public Animator createShowUpAnimator(final Key key, final KeyPreviewView keyPreviewView) {
169ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        final Animator animator = mParams.createShowUpAnimator(keyPreviewView);
170ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        animator.addListener(new AnimatorListenerAdapter() {
171bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            @Override
172ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            public void onAnimationStart(final Animator animator) {
173615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka                showKeyPreview(key, keyPreviewView, false /* withAnimation */);
174bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            }
175bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        });
176ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        return animator;
177bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
178bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
179ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka    private Animator createDismissAnimator(final Key key, final KeyPreviewView keyPreviewView) {
180ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        final Animator animator = mParams.createDismissAnimator(keyPreviewView);
181ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        animator.addListener(new AnimatorListenerAdapter() {
182bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            @Override
183ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            public void onAnimationEnd(final Animator animator) {
184bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka                dismissKeyPreview(key, false /* withAnimation */);
185bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            }
186bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        });
187ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        return animator;
188bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
189bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
190ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka    private static class KeyPreviewAnimators extends AnimatorListenerAdapter {
191ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        private final Animator mShowUpAnimator;
192ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        private final Animator mDismissAnimator;
193bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
194ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        public KeyPreviewAnimators(final Animator showUpAnimator, final Animator dismissAnimator) {
195ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            mShowUpAnimator = showUpAnimator;
196ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            mDismissAnimator = dismissAnimator;
197bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
198bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
199276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka        public void startShowUp() {
200ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            mShowUpAnimator.start();
201bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
202bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
203276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka        public void startDismiss() {
204ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            if (mShowUpAnimator.isRunning()) {
205ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka                mShowUpAnimator.addListener(this);
206bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka                return;
207bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            }
208ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            mDismissAnimator.start();
209bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
210bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
211bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        @Override
212ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        public void onAnimationEnd(final Animator animator) {
213ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            mDismissAnimator.start();
214bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
215bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
216bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka}
217