MoreKeysKeyboardView.java revision adba09b54ed1b30bf9b24d632165229a0752b144
1ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka/*
2ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka * Copyright (C) 2011 The Android Open Source Project
3ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka *
4ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
5ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka * you may not use this file except in compliance with the License.
6ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka * You may obtain a copy of the License at
7ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka *
8ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
9ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka *
10ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
11ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
12ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka * See the License for the specific language governing permissions and
14ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka * limitations under the License.
15ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka */
16ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka
17ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaokapackage com.android.inputmethod.keyboard;
18ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka
19ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaokaimport android.content.Context;
20ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaokaimport android.util.AttributeSet;
2135580bad6f3da3b204653825bbb6871563e70728Tom Ouyangimport android.view.MotionEvent;
22ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaokaimport android.view.View;
237f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaokaimport android.view.ViewGroup;
24ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka
2562316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibilityUtils;
2662316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaokaimport com.android.inputmethod.accessibility.MoreKeysKeyboardAccessibilityDelegate;
27ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaokaimport com.android.inputmethod.latin.Constants;
28e07b51e7c65220ac183546103010dd617d164f60Tadashi G. Takaokaimport com.android.inputmethod.latin.R;
29e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CoordinateUtils;
30e07b51e7c65220ac183546103010dd617d164f60Tadashi G. Takaoka
31ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka/**
322affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka * A view that renders a virtual {@link MoreKeysKeyboard}. It handles rendering of keys and
332affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka * detecting key presses and touch movements.
34ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka */
3535580bad6f3da3b204653825bbb6871563e70728Tom Ouyangpublic class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel {
36359c35e0f6e534d096efc1d9f2ff585139e3b3acTadashi G. Takaoka    private final int[] mCoordinates = CoordinateUtils.newInstance();
37ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka
381dbeb251b2570dd3025dcd7134090de0fc860d04Tadashi G. Takaoka    protected final KeyDetector mKeyDetector;
3909e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka    private Controller mController = EMPTY_CONTROLLER;
4035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    protected KeyboardActionListener mListener;
41ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka    private int mOriginX;
42ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka    private int mOriginY;
4335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    private Key mCurrentKey;
4463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka
4535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    private int mActivePointerId;
46ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka
47aea429200e997762cd92744a2b1f3f586fc00b35Tadashi G. Takaoka    protected MoreKeysKeyboardAccessibilityDelegate mAccessibilityDelegate;
4862316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka
49bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka    public MoreKeysKeyboardView(final Context context, final AttributeSet attrs) {
502affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka        this(context, attrs, R.attr.moreKeysKeyboardViewStyle);
51ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka    }
52ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka
53bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka    public MoreKeysKeyboardView(final Context context, final AttributeSet attrs,
54bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka            final int defStyle) {
55ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka        super(context, attrs, defStyle);
5662316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka        mKeyDetector = new MoreKeysDetector(getResources().getDimension(
5762316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka                R.dimen.config_more_keys_keyboard_slide_allowance));
58ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka    }
59ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka
60ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka    @Override
61bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
6238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        final Keyboard keyboard = getKeyboard();
6338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        if (keyboard != null) {
648da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka            final int width = keyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight();
658da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka            final int height = keyboard.mOccupiedHeight + getPaddingTop() + getPaddingBottom();
6638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            setMeasuredDimension(width, height);
6738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        } else {
6838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
6938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        }
7038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka    }
7138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
7238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka    @Override
73bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka    public void setKeyboard(final Keyboard keyboard) {
7463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka        super.setKeyboard(keyboard);
751dbeb251b2570dd3025dcd7134090de0fc860d04Tadashi G. Takaoka        mKeyDetector.setKeyboard(
761dbeb251b2570dd3025dcd7134090de0fc860d04Tadashi G. Takaoka                keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection());
7762316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka        if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
78dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka            if (mAccessibilityDelegate == null) {
79dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka                mAccessibilityDelegate = new MoreKeysKeyboardAccessibilityDelegate(
80dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka                        this, mKeyDetector);
81dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka                mAccessibilityDelegate.setOpenAnnounce(R.string.spoken_open_more_keys_keyboard);
82dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka                mAccessibilityDelegate.setCloseAnnounce(R.string.spoken_close_more_keys_keyboard);
83dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka            }
8462316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka            mAccessibilityDelegate.setKeyboard(keyboard);
8562316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka        } else {
8662316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka            mAccessibilityDelegate = null;
8762316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka        }
8863c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka    }
8963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka
9063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka    @Override
91bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka    public void showMoreKeysPanel(final View parentView, final Controller controller,
92fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang            final int pointX, final int pointY, final KeyboardActionListener listener) {
93f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka        mController = controller;
94f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka        mListener = listener;
95fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        final View container = getContainerView();
96bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka        // The coordinates of panel's left-top corner in parentView's coordinate system.
972fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        // We need to consider background drawable paddings.
982fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final int x = pointX - getDefaultCoordX() - container.getPaddingLeft() - getPaddingLeft();
992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom()
1002fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                + getPaddingBottom();
101ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka
102bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka        parentView.getLocationInWindow(mCoordinates);
1032fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        // Ensure the horizontal position of the panel does not extend past the parentView edges.
104fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        final int maxX = parentView.getMeasuredWidth() - container.getMeasuredWidth();
105be68b41ccb1a16201c3b91f1576a731f7715aaf6Tom Ouyang        final int panelX = Math.max(0, Math.min(maxX, x)) + CoordinateUtils.x(mCoordinates);
106fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        final int panelY = y + CoordinateUtils.y(mCoordinates);
107fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        container.setX(panelX);
108fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        container.setY(panelY);
109ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka
110bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka        mOriginX = x + container.getPaddingLeft();
111bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka        mOriginY = y + container.getPaddingTop();
112fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        controller.onShowMoreKeysPanel(this);
11362316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka        final MoreKeysKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
11462316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka        if (accessibilityDelegate != null) {
11562316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka            accessibilityDelegate.onShowMoreKeysKeyboard();
11662316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka        }
117f3f3189adbce15d609d5e06632f8e0630db890d1Tadashi G. Takaoka    }
118f3f3189adbce15d609d5e06632f8e0630db890d1Tadashi G. Takaoka
11935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    /**
12035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang     * Returns the default x coordinate for showing this panel.
12135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang     */
12235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    protected int getDefaultCoordX() {
12335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        return ((MoreKeysKeyboard)getKeyboard()).getDefaultCoordX();
12435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    }
12535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang
12635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    @Override
12735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    public void onDownEvent(final int x, final int y, final int pointerId, final long eventTime) {
12835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        mActivePointerId = pointerId;
129adba09b54ed1b30bf9b24d632165229a0752b144Tadashi G. Takaoka        mCurrentKey = detectKey(x, y);
13035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    }
13135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang
13235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    @Override
133fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka    public void onMoveEvent(final int x, final int y, final int pointerId, final long eventTime) {
134ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang        if (mActivePointerId != pointerId) {
135ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang            return;
136ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang        }
137ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang        final boolean hasOldKey = (mCurrentKey != null);
138adba09b54ed1b30bf9b24d632165229a0752b144Tadashi G. Takaoka        mCurrentKey = detectKey(x, y);
139ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang        if (hasOldKey && mCurrentKey == null) {
140fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka            // A more keys keyboard is canceled when detecting no key.
1411f215a58c99f0eb2f536e9cccd51371f2883e201Tadashi G. Takaoka            mController.onCancelMoreKeysPanel();
142ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang        }
14335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    }
14435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang
14535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    @Override
14635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    public void onUpEvent(final int x, final int y, final int pointerId, final long eventTime) {
147fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka        if (mActivePointerId != pointerId) {
148fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka            return;
149fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka        }
150fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka        // Calling {@link #detectKey(int,int,int)} here is harmless because the last move event and
151fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka        // the following up event share the same coordinates.
152adba09b54ed1b30bf9b24d632165229a0752b144Tadashi G. Takaoka        mCurrentKey = detectKey(x, y);
153fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka        if (mCurrentKey != null) {
15435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang            updateReleaseKeyGraphics(mCurrentKey);
1555fc1510bc1cbe9bcd1105a403e07b5400470ae96Tadashi G. Takaoka            onKeyInput(mCurrentKey, x, y);
15635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang            mCurrentKey = null;
15735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        }
15835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    }
15935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang
16035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    /**
16135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang     * Performs the specific action for this panel when the user presses a key on the panel.
16235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang     */
1635fc1510bc1cbe9bcd1105a403e07b5400470ae96Tadashi G. Takaoka    protected void onKeyInput(final Key key, final int x, final int y) {
1645fc1510bc1cbe9bcd1105a403e07b5400470ae96Tadashi G. Takaoka        final int code = key.getCode();
16535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        if (code == Constants.CODE_OUTPUT_TEXT) {
16635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang            mListener.onTextInput(mCurrentKey.getOutputText());
16735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        } else if (code != Constants.CODE_UNSPECIFIED) {
168a91dfff5e54f68c4003327eeca47286084c35a2fJean Chalard            if (getKeyboard().hasProximityCharsCorrection(code)) {
1692282e8520a2c1984989a14fb09896536f5033b26Jean Chalard                mListener.onCodeInput(code, x, y, false /* isKeyRepeat */);
170a91dfff5e54f68c4003327eeca47286084c35a2fJean Chalard            } else {
1712282e8520a2c1984989a14fb09896536f5033b26Jean Chalard                mListener.onCodeInput(code, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
1722282e8520a2c1984989a14fb09896536f5033b26Jean Chalard                        false /* isKeyRepeat */);
173a91dfff5e54f68c4003327eeca47286084c35a2fJean Chalard            }
17435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        }
17535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    }
17635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang
177adba09b54ed1b30bf9b24d632165229a0752b144Tadashi G. Takaoka    private Key detectKey(int x, int y) {
17835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        final Key oldKey = mCurrentKey;
17935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        final Key newKey = mKeyDetector.detectHitKey(x, y);
180fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka        if (newKey == oldKey) {
181fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka            return newKey;
182fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka        }
183fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka        // A new key is detected.
184fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka        if (oldKey != null) {
185fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka            updateReleaseKeyGraphics(oldKey);
186fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka            invalidateKey(oldKey);
187fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka        }
188fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka        if (newKey != null) {
189fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka            updatePressKeyGraphics(newKey);
190fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka            invalidateKey(newKey);
19135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        }
192fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka        return newKey;
19335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    }
19435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang
19535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    private void updateReleaseKeyGraphics(final Key key) {
19635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        key.onReleased();
19735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        invalidateKey(key);
19835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    }
19935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang
20035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    private void updatePressKeyGraphics(final Key key) {
20135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        key.onPressed();
20235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        invalidateKey(key);
20335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    }
20435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang
205ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka    @Override
20609e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka    public void dismissMoreKeysPanel() {
20709e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka        if (!isShowingInParent()) {
20809e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka            return;
20909e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka        }
210a2e365da0acf80c1bcd8413d72f697a0da374779Tadashi G. Takaoka        final MoreKeysKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
211a2e365da0acf80c1bcd8413d72f697a0da374779Tadashi G. Takaoka        if (accessibilityDelegate != null) {
212a2e365da0acf80c1bcd8413d72f697a0da374779Tadashi G. Takaoka            accessibilityDelegate.onDismissMoreKeysKeyboard();
213a2e365da0acf80c1bcd8413d72f697a0da374779Tadashi G. Takaoka        }
2141f215a58c99f0eb2f536e9cccd51371f2883e201Tadashi G. Takaoka        mController.onDismissMoreKeysPanel();
2159ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka    }
2169ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka
2179ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka    @Override
218bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka    public int translateX(final int x) {
21963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka        return x - mOriginX;
22063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka    }
22163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka
22263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka    @Override
223bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka    public int translateY(final int y) {
22463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka        return y - mOriginY;
225ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka    }
226fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang
227fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang    @Override
22835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    public boolean onTouchEvent(final MotionEvent me) {
22935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        final int action = me.getActionMasked();
23035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        final long eventTime = me.getEventTime();
23135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        final int index = me.getActionIndex();
23235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        final int x = (int)me.getX(index);
23335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        final int y = (int)me.getY(index);
23435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        final int pointerId = me.getPointerId(index);
23535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        switch (action) {
23635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        case MotionEvent.ACTION_DOWN:
23735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        case MotionEvent.ACTION_POINTER_DOWN:
23835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang            onDownEvent(x, y, pointerId, eventTime);
23935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang            break;
24035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        case MotionEvent.ACTION_UP:
24135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        case MotionEvent.ACTION_POINTER_UP:
24235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang            onUpEvent(x, y, pointerId, eventTime);
24335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang            break;
24435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        case MotionEvent.ACTION_MOVE:
24535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang            onMoveEvent(x, y, pointerId, eventTime);
24635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang            break;
24735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        }
24833482a9b9ccf605c63fab7c9b8273a240bbc2035Tadashi G. Takaoka        return true;
24935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang    }
25035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang
25162316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka    /**
25262316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka     * {@inheritDoc}
25362316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka     */
25462316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka    @Override
25562316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka    public boolean onHoverEvent(final MotionEvent event) {
25662316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka        final MoreKeysKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
25762316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka        if (accessibilityDelegate != null) {
25862316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka            return accessibilityDelegate.onHoverEvent(event);
25962316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka        }
26062316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka        return super.onHoverEvent(event);
26162316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka    }
26262316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka
2637f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka    private View getContainerView() {
264fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        return (View)getParent();
265fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang    }
266fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang
267fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang    @Override
2687f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka    public void showInParent(final ViewGroup parentView) {
2697f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka        removeFromParent();
2707f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka        parentView.addView(getContainerView());
2717f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka    }
2727f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka
2737f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka    @Override
2747f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka    public void removeFromParent() {
2757f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka        final View containerView = getContainerView();
2767f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka        final ViewGroup currentParent = (ViewGroup)containerView.getParent();
2777f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka        if (currentParent != null) {
2787f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka            currentParent.removeView(containerView);
2797f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka        }
2807f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka    }
2817f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka
2827f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka    @Override
283fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang    public boolean isShowingInParent() {
284fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        return (getContainerView().getParent() != null);
285fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang    }
286ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka}
287