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; 20727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaokaimport android.content.res.TypedArray; 21727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaokaimport android.graphics.Canvas; 22727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaokaimport android.graphics.Paint; 23727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaokaimport android.graphics.drawable.Drawable; 24ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaokaimport android.util.AttributeSet; 2535580bad6f3da3b204653825bbb6871563e70728Tom Ouyangimport android.view.MotionEvent; 26ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaokaimport android.view.View; 277f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaokaimport android.view.ViewGroup; 28ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 2962316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibilityUtils; 3062316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaokaimport com.android.inputmethod.accessibility.MoreKeysKeyboardAccessibilityDelegate; 31727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyDrawParams; 32e07b51e7c65220ac183546103010dd617d164f60Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 339342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport com.android.inputmethod.latin.common.Constants; 345b91b551e5ffaf2c2e691dfbd434f21c82293986Jean Chalardimport com.android.inputmethod.latin.common.CoordinateUtils; 35e07b51e7c65220ac183546103010dd617d164f60Tadashi G. Takaoka 36ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka/** 372affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka * A view that renders a virtual {@link MoreKeysKeyboard}. It handles rendering of keys and 382affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka * detecting key presses and touch movements. 39ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka */ 4035580bad6f3da3b204653825bbb6871563e70728Tom Ouyangpublic class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel { 41359c35e0f6e534d096efc1d9f2ff585139e3b3acTadashi G. Takaoka private final int[] mCoordinates = CoordinateUtils.newInstance(); 42ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 43727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka private final Drawable mDivider; 441dbeb251b2570dd3025dcd7134090de0fc860d04Tadashi G. Takaoka protected final KeyDetector mKeyDetector; 4509e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka private Controller mController = EMPTY_CONTROLLER; 4635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang protected KeyboardActionListener mListener; 47ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka private int mOriginX; 48ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka private int mOriginY; 4935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private Key mCurrentKey; 5063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 5135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private int mActivePointerId; 52ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 53aea429200e997762cd92744a2b1f3f586fc00b35Tadashi G. Takaoka protected MoreKeysKeyboardAccessibilityDelegate mAccessibilityDelegate; 5462316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka 55bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public MoreKeysKeyboardView(final Context context, final AttributeSet attrs) { 562affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka this(context, attrs, R.attr.moreKeysKeyboardViewStyle); 57ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka } 58ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 59bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public MoreKeysKeyboardView(final Context context, final AttributeSet attrs, 60bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final int defStyle) { 61ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka super(context, attrs, defStyle); 62727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka final TypedArray moreKeysKeyboardViewAttr = context.obtainStyledAttributes(attrs, 63727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka R.styleable.MoreKeysKeyboardView, defStyle, R.style.MoreKeysKeyboardView); 64727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka mDivider = moreKeysKeyboardViewAttr.getDrawable(R.styleable.MoreKeysKeyboardView_divider); 65727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka if (mDivider != null) { 66727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka // TODO: Drawable itself should have an alpha value. 67727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka mDivider.setAlpha(128); 68727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka } 69727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka moreKeysKeyboardViewAttr.recycle(); 7062316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka mKeyDetector = new MoreKeysDetector(getResources().getDimension( 7162316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka R.dimen.config_more_keys_keyboard_slide_allowance)); 72ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka } 73ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 74ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka @Override 75bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { 7638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 7738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka if (keyboard != null) { 788da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka final int width = keyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight(); 798da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka final int height = keyboard.mOccupiedHeight + getPaddingTop() + getPaddingBottom(); 8038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka setMeasuredDimension(width, height); 8138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } else { 8238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka super.onMeasure(widthMeasureSpec, heightMeasureSpec); 8338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 8438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 8538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 8638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka @Override 87727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka protected void onDrawKeyTopVisuals(final Key key, final Canvas canvas, final Paint paint, 88727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka final KeyDrawParams params) { 89727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka if (!key.isSpacer() || !(key instanceof MoreKeysKeyboard.MoreKeyDivider) 90727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka || mDivider == null) { 91727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka super.onDrawKeyTopVisuals(key, canvas, paint, params); 92727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka return; 93727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka } 94727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka final int keyWidth = key.getDrawWidth(); 95727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka final int keyHeight = key.getHeight(); 96727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka final int iconWidth = Math.min(mDivider.getIntrinsicWidth(), keyWidth); 97727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka final int iconHeight = mDivider.getIntrinsicHeight(); 98727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka final int iconX = (keyWidth - iconWidth) / 2; // Align horizontally center 99727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka final int iconY = (keyHeight - iconHeight) / 2; // Align vertically center 100727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka drawIcon(canvas, mDivider, iconX, iconY, iconWidth, iconHeight); 101727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka } 102727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka 103727e818e95ef68460ebafb2eb3b11c23a2d8fcd8Tadashi G. Takaoka @Override 104bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void setKeyboard(final Keyboard keyboard) { 10563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka super.setKeyboard(keyboard); 1061dbeb251b2570dd3025dcd7134090de0fc860d04Tadashi G. Takaoka mKeyDetector.setKeyboard( 1071dbeb251b2570dd3025dcd7134090de0fc860d04Tadashi G. Takaoka keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection()); 10804cd8794e04b14c2b7e7eed036b83075792134a1Tadashi G. Takaoka if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) { 109dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka if (mAccessibilityDelegate == null) { 110dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka mAccessibilityDelegate = new MoreKeysKeyboardAccessibilityDelegate( 111dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka this, mKeyDetector); 112dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka mAccessibilityDelegate.setOpenAnnounce(R.string.spoken_open_more_keys_keyboard); 113dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka mAccessibilityDelegate.setCloseAnnounce(R.string.spoken_close_more_keys_keyboard); 114dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka } 11562316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka mAccessibilityDelegate.setKeyboard(keyboard); 11662316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka } else { 11762316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka mAccessibilityDelegate = null; 11862316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka } 11963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 12063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 12163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka @Override 122bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void showMoreKeysPanel(final View parentView, final Controller controller, 123fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang final int pointX, final int pointY, final KeyboardActionListener listener) { 124f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka mController = controller; 125f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka mListener = listener; 126fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang final View container = getContainerView(); 127bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka // The coordinates of panel's left-top corner in parentView's coordinate system. 1282fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // We need to consider background drawable paddings. 1292fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final int x = pointX - getDefaultCoordX() - container.getPaddingLeft() - getPaddingLeft(); 1302fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom() 1312fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa + getPaddingBottom(); 132ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 133bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka parentView.getLocationInWindow(mCoordinates); 1342fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Ensure the horizontal position of the panel does not extend past the parentView edges. 135fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang final int maxX = parentView.getMeasuredWidth() - container.getMeasuredWidth(); 136be68b41ccb1a16201c3b91f1576a731f7715aaf6Tom Ouyang final int panelX = Math.max(0, Math.min(maxX, x)) + CoordinateUtils.x(mCoordinates); 137fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang final int panelY = y + CoordinateUtils.y(mCoordinates); 138fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang container.setX(panelX); 139fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang container.setY(panelY); 140ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 141bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka mOriginX = x + container.getPaddingLeft(); 142bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka mOriginY = y + container.getPaddingTop(); 143fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang controller.onShowMoreKeysPanel(this); 14462316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka final MoreKeysKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate; 14504cd8794e04b14c2b7e7eed036b83075792134a1Tadashi G. Takaoka if (accessibilityDelegate != null 14604cd8794e04b14c2b7e7eed036b83075792134a1Tadashi G. Takaoka && AccessibilityUtils.getInstance().isAccessibilityEnabled()) { 14762316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka accessibilityDelegate.onShowMoreKeysKeyboard(); 14862316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka } 149f3f3189adbce15d609d5e06632f8e0630db890d1Tadashi G. Takaoka } 150f3f3189adbce15d609d5e06632f8e0630db890d1Tadashi G. Takaoka 15135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang /** 15235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang * Returns the default x coordinate for showing this panel. 15335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang */ 15435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang protected int getDefaultCoordX() { 15535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang return ((MoreKeysKeyboard)getKeyboard()).getDefaultCoordX(); 15635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 15735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 15835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang @Override 15935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang public void onDownEvent(final int x, final int y, final int pointerId, final long eventTime) { 16035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mActivePointerId = pointerId; 161adba09b54ed1b30bf9b24d632165229a0752b144Tadashi G. Takaoka mCurrentKey = detectKey(x, y); 16235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 16335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 16435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang @Override 165fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka public void onMoveEvent(final int x, final int y, final int pointerId, final long eventTime) { 166ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (mActivePointerId != pointerId) { 167ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang return; 168ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 169ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang final boolean hasOldKey = (mCurrentKey != null); 170adba09b54ed1b30bf9b24d632165229a0752b144Tadashi G. Takaoka mCurrentKey = detectKey(x, y); 171ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (hasOldKey && mCurrentKey == null) { 172fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka // A more keys keyboard is canceled when detecting no key. 1731f215a58c99f0eb2f536e9cccd51371f2883e201Tadashi G. Takaoka mController.onCancelMoreKeysPanel(); 174ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 17535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 17635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 17735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang @Override 17835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang public void onUpEvent(final int x, final int y, final int pointerId, final long eventTime) { 179fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka if (mActivePointerId != pointerId) { 180fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka return; 181fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka } 182fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka // Calling {@link #detectKey(int,int,int)} here is harmless because the last move event and 183fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka // the following up event share the same coordinates. 184adba09b54ed1b30bf9b24d632165229a0752b144Tadashi G. Takaoka mCurrentKey = detectKey(x, y); 185fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka if (mCurrentKey != null) { 18635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang updateReleaseKeyGraphics(mCurrentKey); 1875fc1510bc1cbe9bcd1105a403e07b5400470ae96Tadashi G. Takaoka onKeyInput(mCurrentKey, x, y); 18835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mCurrentKey = null; 18935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 19035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 19135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 19235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang /** 19335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang * Performs the specific action for this panel when the user presses a key on the panel. 19435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang */ 1955fc1510bc1cbe9bcd1105a403e07b5400470ae96Tadashi G. Takaoka protected void onKeyInput(final Key key, final int x, final int y) { 1965fc1510bc1cbe9bcd1105a403e07b5400470ae96Tadashi G. Takaoka final int code = key.getCode(); 19735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang if (code == Constants.CODE_OUTPUT_TEXT) { 19835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mListener.onTextInput(mCurrentKey.getOutputText()); 19935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } else if (code != Constants.CODE_UNSPECIFIED) { 200a91dfff5e54f68c4003327eeca47286084c35a2fJean Chalard if (getKeyboard().hasProximityCharsCorrection(code)) { 2012282e8520a2c1984989a14fb09896536f5033b26Jean Chalard mListener.onCodeInput(code, x, y, false /* isKeyRepeat */); 202a91dfff5e54f68c4003327eeca47286084c35a2fJean Chalard } else { 2032282e8520a2c1984989a14fb09896536f5033b26Jean Chalard mListener.onCodeInput(code, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, 2042282e8520a2c1984989a14fb09896536f5033b26Jean Chalard false /* isKeyRepeat */); 205a91dfff5e54f68c4003327eeca47286084c35a2fJean Chalard } 20635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 20735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 20835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 209adba09b54ed1b30bf9b24d632165229a0752b144Tadashi G. Takaoka private Key detectKey(int x, int y) { 21035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final Key oldKey = mCurrentKey; 21135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final Key newKey = mKeyDetector.detectHitKey(x, y); 212fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka if (newKey == oldKey) { 213fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka return newKey; 214fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka } 215fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka // A new key is detected. 216fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka if (oldKey != null) { 217fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka updateReleaseKeyGraphics(oldKey); 218fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka invalidateKey(oldKey); 219fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka } 220fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka if (newKey != null) { 221fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka updatePressKeyGraphics(newKey); 222fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka invalidateKey(newKey); 22335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 224fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka return newKey; 22535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 22635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 22735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private void updateReleaseKeyGraphics(final Key key) { 22835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang key.onReleased(); 22935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang invalidateKey(key); 23035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 23135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 23235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private void updatePressKeyGraphics(final Key key) { 23335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang key.onPressed(); 23435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang invalidateKey(key); 23535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 23635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 237ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka @Override 23809e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka public void dismissMoreKeysPanel() { 23909e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka if (!isShowingInParent()) { 24009e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka return; 24109e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka } 242a2e365da0acf80c1bcd8413d72f697a0da374779Tadashi G. Takaoka final MoreKeysKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate; 24304cd8794e04b14c2b7e7eed036b83075792134a1Tadashi G. Takaoka if (accessibilityDelegate != null 24404cd8794e04b14c2b7e7eed036b83075792134a1Tadashi G. Takaoka && AccessibilityUtils.getInstance().isAccessibilityEnabled()) { 245a2e365da0acf80c1bcd8413d72f697a0da374779Tadashi G. Takaoka accessibilityDelegate.onDismissMoreKeysKeyboard(); 246a2e365da0acf80c1bcd8413d72f697a0da374779Tadashi G. Takaoka } 2471f215a58c99f0eb2f536e9cccd51371f2883e201Tadashi G. Takaoka mController.onDismissMoreKeysPanel(); 2489ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 2499ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 2509ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka @Override 251bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public int translateX(final int x) { 25263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return x - mOriginX; 25363c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 25463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 25563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka @Override 256bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public int translateY(final int y) { 25763c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return y - mOriginY; 258ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka } 259fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang 260fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang @Override 26135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang public boolean onTouchEvent(final MotionEvent me) { 26235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int action = me.getActionMasked(); 26335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final long eventTime = me.getEventTime(); 26435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int index = me.getActionIndex(); 26535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int x = (int)me.getX(index); 26635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int y = (int)me.getY(index); 26735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int pointerId = me.getPointerId(index); 26835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang switch (action) { 26935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang case MotionEvent.ACTION_DOWN: 27035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang case MotionEvent.ACTION_POINTER_DOWN: 27135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onDownEvent(x, y, pointerId, eventTime); 27235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang break; 27335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang case MotionEvent.ACTION_UP: 27435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang case MotionEvent.ACTION_POINTER_UP: 27535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEvent(x, y, pointerId, eventTime); 27635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang break; 27735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang case MotionEvent.ACTION_MOVE: 27835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onMoveEvent(x, y, pointerId, eventTime); 27935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang break; 28035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 28133482a9b9ccf605c63fab7c9b8273a240bbc2035Tadashi G. Takaoka return true; 28235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 28335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 28462316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka /** 28562316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka * {@inheritDoc} 28662316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka */ 28762316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka @Override 28862316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka public boolean onHoverEvent(final MotionEvent event) { 28962316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka final MoreKeysKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate; 29004cd8794e04b14c2b7e7eed036b83075792134a1Tadashi G. Takaoka if (accessibilityDelegate != null 29104cd8794e04b14c2b7e7eed036b83075792134a1Tadashi G. Takaoka && AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 29262316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka return accessibilityDelegate.onHoverEvent(event); 29362316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka } 29462316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka return super.onHoverEvent(event); 29562316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka } 29662316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka 2977f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka private View getContainerView() { 298fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang return (View)getParent(); 299fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang } 300fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang 301fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang @Override 3027f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka public void showInParent(final ViewGroup parentView) { 3037f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka removeFromParent(); 3047f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka parentView.addView(getContainerView()); 3057f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka } 3067f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka 3077f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka @Override 3087f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka public void removeFromParent() { 3097f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka final View containerView = getContainerView(); 3107f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka final ViewGroup currentParent = (ViewGroup)containerView.getParent(); 3117f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka if (currentParent != null) { 3127f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka currentParent.removeView(containerView); 3137f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka } 3147f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka } 3157f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka 3167f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka @Override 317fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang public boolean isShowingInParent() { 318fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang return (getContainerView().getParent() != null); 319fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang } 320ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka} 321