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;
265b91b551e5ffaf2c2e691dfbd434f21c82293986Jean Chalardimport com.android.inputmethod.latin.common.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. Takaoka
32bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka/**
33bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * This class controls pop up key previews. This class decides:
34bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * - what kind of key previews should be shown.
35bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * - where key previews should be placed.
36bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka * - how key previews should be shown and dismissed.
37bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka */
38bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokapublic final class KeyPreviewChoreographer {
39615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    // Free {@link KeyPreviewView} pool that can be used for key preview.
40615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    private final ArrayDeque<KeyPreviewView> mFreeKeyPreviewViews = new ArrayDeque<>();
41615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    // Map from {@link Key} to {@link KeyPreviewView} that is currently being displayed as key
42615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    // preview.
43615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    private final HashMap<Key,KeyPreviewView> mShowingKeyPreviewViews = new HashMap<>();
44bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
45bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    private final KeyPreviewDrawParams mParams;
46bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
47bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    public KeyPreviewChoreographer(final KeyPreviewDrawParams params) {
48bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        mParams = params;
49bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
50bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
51615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    public KeyPreviewView getKeyPreviewView(final Key key, final ViewGroup placerView) {
52615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        KeyPreviewView keyPreviewView = mShowingKeyPreviewViews.remove(key);
53615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        if (keyPreviewView != null) {
54615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka            return keyPreviewView;
55bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
56615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView = mFreeKeyPreviewViews.poll();
57615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        if (keyPreviewView != null) {
58615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka            return keyPreviewView;
59bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
60bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        final Context context = placerView.getContext();
61615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView = new KeyPreviewView(context, null /* attrs */);
62615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.setBackgroundResource(mParams.mPreviewBackgroundResId);
63615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        placerView.addView(keyPreviewView, ViewLayoutUtils.newLayoutParam(placerView, 0, 0));
64615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        return keyPreviewView;
65bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
66bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
67bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    public boolean isShowingKeyPreview(final Key key) {
68615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        return mShowingKeyPreviewViews.containsKey(key);
69bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
70bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
71bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    public void dismissKeyPreview(final Key key, final boolean withAnimation) {
72bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        if (key == null) {
73bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            return;
74bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
75615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        final KeyPreviewView keyPreviewView = mShowingKeyPreviewViews.get(key);
76615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        if (keyPreviewView == null) {
77bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            return;
78bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
79615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        final Object tag = keyPreviewView.getTag();
80bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        if (withAnimation) {
81ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            if (tag instanceof KeyPreviewAnimators) {
82ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka                final KeyPreviewAnimators animators = (KeyPreviewAnimators)tag;
83ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka                animators.startDismiss();
847e9b0b42bfd5c51f4bc236a73df3f14cf583c989Tadashi G. Takaoka                return;
85bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            }
86bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
87bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        // Dismiss preview without animation.
88615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        mShowingKeyPreviewViews.remove(key);
89bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        if (tag instanceof Animator) {
90bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            ((Animator)tag).cancel();
91bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
92615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.setTag(null);
93615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.setVisibility(View.INVISIBLE);
94615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        mFreeKeyPreviewViews.add(keyPreviewView);
95bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
96bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
9784405d2a6815a99992849e821e073835f2d892e3Tadashi G. Takaoka    public void placeAndShowKeyPreview(final Key key, final KeyboardIconsSet iconsSet,
983ff72dd0daa9baaeb4d6b8ade59d65c1f0e8b34fTadashi G. Takaoka            final KeyDrawParams drawParams, final int keyboardViewWidth, final int[] keyboardOrigin,
993ff72dd0daa9baaeb4d6b8ade59d65c1f0e8b34fTadashi G. Takaoka            final ViewGroup placerView, final boolean withAnimation) {
100615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        final KeyPreviewView keyPreviewView = getKeyPreviewView(key, placerView);
1013ff72dd0daa9baaeb4d6b8ade59d65c1f0e8b34fTadashi G. Takaoka        placeKeyPreview(
102615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka                key, keyPreviewView, iconsSet, drawParams, keyboardViewWidth, keyboardOrigin);
103615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        showKeyPreview(key, keyPreviewView, withAnimation);
1043ff72dd0daa9baaeb4d6b8ade59d65c1f0e8b34fTadashi G. Takaoka    }
1053ff72dd0daa9baaeb4d6b8ade59d65c1f0e8b34fTadashi G. Takaoka
106615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka    private void placeKeyPreview(final Key key, final KeyPreviewView keyPreviewView,
107bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            final KeyboardIconsSet iconsSet, final KeyDrawParams drawParams,
108bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            final int keyboardViewWidth, final int[] originCoords) {
109615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.setPreviewVisual(key, iconsSet, drawParams);
110615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.measure(
111bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
112615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        mParams.setGeometry(keyPreviewView);
113615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        final int previewWidth = keyPreviewView.getMeasuredWidth();
114bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        final int previewHeight = mParams.mPreviewHeight;
115bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        final int keyDrawWidth = key.getDrawWidth();
116bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        // The key preview is horizontally aligned with the center of the visible part of the
117bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        // parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and
118bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        // the left/right background is used if such background is specified.
119615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        final int keyPreviewPosition;
120bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2
121bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka                + CoordinateUtils.x(originCoords);
122bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        if (previewX < 0) {
123bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            previewX = 0;
124615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka            keyPreviewPosition = KeyPreviewView.POSITION_LEFT;
125bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        } else if (previewX > keyboardViewWidth - previewWidth) {
126bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            previewX = keyboardViewWidth - previewWidth;
127615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka            keyPreviewPosition = KeyPreviewView.POSITION_RIGHT;
128bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        } else {
129615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka            keyPreviewPosition = KeyPreviewView.POSITION_MIDDLE;
130bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
131615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        final boolean hasMoreKeys = (key.getMoreKeys() != null);
132615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.setPreviewBackground(hasMoreKeys, keyPreviewPosition);
133bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        // The key preview is placed vertically above the top edge of the parent key with an
134bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        // arbitrary offset.
135bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        final int previewY = key.getY() - previewHeight + mParams.mPreviewOffset
136bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka                + CoordinateUtils.y(originCoords);
137bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
138bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        ViewLayoutUtils.placeViewAt(
139615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka                keyPreviewView, previewX, previewY, previewWidth, previewHeight);
140615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.setPivotX(previewWidth / 2.0f);
141615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka        keyPreviewView.setPivotY(previewHeight);
142bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
143bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
1445f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    void showKeyPreview(final Key key, final KeyPreviewView keyPreviewView,
145bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            final boolean withAnimation) {
146bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        if (!withAnimation) {
147615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka            keyPreviewView.setVisibility(View.VISIBLE);
148615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka            mShowingKeyPreviewViews.put(key, keyPreviewView);
149bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            return;
150bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
151bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
152bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        // Show preview with animation.
153ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        final Animator showUpAnimator = createShowUpAnimator(key, keyPreviewView);
154ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        final Animator dismissAnimator = createDismissAnimator(key, keyPreviewView);
155ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        final KeyPreviewAnimators animators = new KeyPreviewAnimators(
156ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka                showUpAnimator, dismissAnimator);
157ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        keyPreviewView.setTag(animators);
158ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        animators.startShowUp();
159bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
160bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
161ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka    public Animator createShowUpAnimator(final Key key, final KeyPreviewView keyPreviewView) {
1625f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final Animator showUpAnimator = mParams.createShowUpAnimator(keyPreviewView);
1635f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        showUpAnimator.addListener(new AnimatorListenerAdapter() {
164bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            @Override
165ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            public void onAnimationStart(final Animator animator) {
166615f431465ed2b5f3511ddfcc4c6de7bbfc28151Tadashi G. Takaoka                showKeyPreview(key, keyPreviewView, false /* withAnimation */);
167bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            }
168bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        });
1695f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        return showUpAnimator;
170bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
171bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
172ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka    private Animator createDismissAnimator(final Key key, final KeyPreviewView keyPreviewView) {
1735f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final Animator dismissAnimator = mParams.createDismissAnimator(keyPreviewView);
1745f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        dismissAnimator.addListener(new AnimatorListenerAdapter() {
175bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            @Override
176ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            public void onAnimationEnd(final Animator animator) {
177bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka                dismissKeyPreview(key, false /* withAnimation */);
178bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            }
179bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        });
1805f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        return dismissAnimator;
181bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
182bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
183ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka    private static class KeyPreviewAnimators extends AnimatorListenerAdapter {
184ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        private final Animator mShowUpAnimator;
185ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        private final Animator mDismissAnimator;
186bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
187ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        public KeyPreviewAnimators(final Animator showUpAnimator, final Animator dismissAnimator) {
188ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            mShowUpAnimator = showUpAnimator;
189ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            mDismissAnimator = dismissAnimator;
190bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
191bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
192276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka        public void startShowUp() {
193ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            mShowUpAnimator.start();
194bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
195bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
196276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka        public void startDismiss() {
197ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            if (mShowUpAnimator.isRunning()) {
198ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka                mShowUpAnimator.addListener(this);
199bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka                return;
200bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka            }
201ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            mDismissAnimator.start();
202bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
203bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
204bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        @Override
205ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        public void onAnimationEnd(final Animator animator) {
206ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            mDismissAnimator.start();
207bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        }
208bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    }
209bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka}
210