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.content.res.Resources; 21ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaokaimport android.util.AttributeSet; 22ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaokaimport android.view.Gravity; 23ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaokaimport android.view.View; 24ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaokaimport android.widget.PopupWindow; 25ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 2663c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; 2763c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker.TimerProxy; 28ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaokaimport com.android.inputmethod.latin.Constants; 2910102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaokaimport com.android.inputmethod.latin.InputPointers; 30e07b51e7c65220ac183546103010dd617d164f60Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 31e07b51e7c65220ac183546103010dd617d164f60Tadashi G. Takaoka 32ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka/** 332affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka * A view that renders a virtual {@link MoreKeysKeyboard}. It handles rendering of keys and 342affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka * detecting key presses and touch movements. 35ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka */ 36a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel { 37ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka private final int[] mCoordinates = new int[2]; 38ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 3963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka private final KeyDetector mKeyDetector; 4063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 41f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka private Controller mController; 42f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka private KeyboardActionListener mListener; 43ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka private int mOriginX; 44ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka private int mOriginY; 4563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 4629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy.Adapter(); 4763c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 482affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka private final KeyboardActionListener mMoreKeysKeyboardListener = 49e3be3bcebc11892b536fdf650f74bba21af13383Tadashi G. Takaoka new KeyboardActionListener.Adapter() { 5063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka @Override 51ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok public void onCodeInput(int primaryCode, int x, int y) { 528dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka // Because a more keys keyboard doesn't need proximity characters correction, we don't 538dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka // send touch event coordinates. 54ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka mListener.onCodeInput( 55ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka primaryCode, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); 5663c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 5763c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 5863c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka @Override 5963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka public void onTextInput(CharSequence text) { 60f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka mListener.onTextInput(text); 6163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 6263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 6363c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka @Override 644be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka public void onStartBatchInput() { 654be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mListener.onStartBatchInput(); 664be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 674be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka 684be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka @Override 6910102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka public void onUpdateBatchInput(InputPointers batchPointers) { 7010102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka mListener.onUpdateBatchInput(batchPointers); 7110102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka } 7210102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka 7310102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka @Override 7410102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka public void onEndBatchInput(InputPointers batchPointers) { 7510102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka mListener.onEndBatchInput(batchPointers); 764be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 774be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka 784be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka @Override 7963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka public void onCancelInput() { 80f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka mListener.onCancelInput(); 8163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 8263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 8363c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka @Override 842a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka public void onPressKey(int primaryCode) { 852a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mListener.onPressKey(primaryCode); 8663c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 872a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka 8863c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka @Override 892a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka public void onReleaseKey(int primaryCode, boolean withSliding) { 902a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mListener.onReleaseKey(primaryCode, withSliding); 9163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 9263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka }; 93ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 942affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka public MoreKeysKeyboardView(Context context, AttributeSet attrs) { 952affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka this(context, attrs, R.attr.moreKeysKeyboardViewStyle); 96ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka } 97ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 982affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka public MoreKeysKeyboardView(Context context, AttributeSet attrs, int defStyle) { 99ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka super(context, attrs, defStyle); 100ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 101ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka final Resources res = context.getResources(); 10250e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka mKeyDetector = new MoreKeysDetector( 1032affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka res.getDimension(R.dimen.more_keys_keyboard_slide_allowance)); 104240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard setKeyPreviewPopupEnabled(false, 0); 105ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka } 106ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 107ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka @Override 10838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 10938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 11038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka if (keyboard != null) { 1118da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka final int width = keyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight(); 1128da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka final int height = keyboard.mOccupiedHeight + getPaddingTop() + getPaddingBottom(); 11338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka setMeasuredDimension(width, height); 11438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } else { 11538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka super.onMeasure(widthMeasureSpec, heightMeasureSpec); 11638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 11738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 11838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 11938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka @Override 12063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka public void setKeyboard(Keyboard keyboard) { 12163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka super.setKeyboard(keyboard); 12263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), 12363c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka -getPaddingTop() + mVerticalCorrection); 12463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 12563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 12663c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka @Override 12763c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka public KeyDetector getKeyDetector() { 12863c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return mKeyDetector; 12963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 13063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 13163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka @Override 13263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka public KeyboardActionListener getKeyboardActionListener() { 1332affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka return mMoreKeysKeyboardListener; 13463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 13563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 13663c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka @Override 13763c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka public DrawingProxy getDrawingProxy() { 1380cf7a45ac53eef7399826a548a2ef8dab225bdf0Tadashi G. Takaoka return this; 13963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 14063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 14163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka @Override 14263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka public TimerProxy getTimerProxy() { 14363c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return EMPTY_TIMER_PROXY; 14463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 14563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 14663c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka @Override 147240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) { 1482affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka // More keys keyboard needs no pop-up key preview displayed, so we pass always false with a 149240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard // delay of 0. The delay does not matter actually since the popup is not shown anyway. 150240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard super.setKeyPreviewPopupEnabled(false, 0); 151f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka } 152f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka 153f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka @Override 1549d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka public void showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY, 155f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka PopupWindow window, KeyboardActionListener listener) { 156f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka mController = controller; 157f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka mListener = listener; 158ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka final View container = (View)getParent(); 159bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka final MoreKeysKeyboard pane = (MoreKeysKeyboard)getKeyboard(); 160bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka final int defaultCoordX = pane.getDefaultCoordX(); 161bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka // The coordinates of panel's left-top corner in parentView's coordinate system. 1627ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka final int x = pointX - defaultCoordX - container.getPaddingLeft(); 1637ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom(); 164ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 165ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka window.setContentView(container); 166ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka window.setWidth(container.getMeasuredWidth()); 167ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka window.setHeight(container.getMeasuredHeight()); 168bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka parentView.getLocationInWindow(mCoordinates); 169bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka window.showAtLocation(parentView, Gravity.NO_GRAVITY, 170bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka x + mCoordinates[0], y + mCoordinates[1]); 171ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka 172bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka mOriginX = x + container.getPaddingLeft(); 173bcbaffd9dd950c6b82c682a742c93f9319d908f5Tadashi G. Takaoka mOriginY = y + container.getPaddingTop(); 174f3f3189adbce15d609d5e06632f8e0630db890d1Tadashi G. Takaoka } 175f3f3189adbce15d609d5e06632f8e0630db890d1Tadashi G. Takaoka 1760cf7a45ac53eef7399826a548a2ef8dab225bdf0Tadashi G. Takaoka private boolean mIsDismissing; 1770cf7a45ac53eef7399826a548a2ef8dab225bdf0Tadashi G. Takaoka 178ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka @Override 1799d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka public boolean dismissMoreKeysPanel() { 18032f4ceb2434b6f204cf8152b406d0f9a642feb73Tadashi G. Takaoka if (mIsDismissing || mController == null) return false; 1810cf7a45ac53eef7399826a548a2ef8dab225bdf0Tadashi G. Takaoka mIsDismissing = true; 1820cf7a45ac53eef7399826a548a2ef8dab225bdf0Tadashi G. Takaoka final boolean dismissed = mController.dismissMoreKeysPanel(); 1830cf7a45ac53eef7399826a548a2ef8dab225bdf0Tadashi G. Takaoka mIsDismissing = false; 1840cf7a45ac53eef7399826a548a2ef8dab225bdf0Tadashi G. Takaoka return dismissed; 1859ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 1869ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 1879ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka @Override 18863c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka public int translateX(int x) { 18963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return x - mOriginX; 19063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 19163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 19263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka @Override 19363c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka public int translateY(int y) { 19463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return y - mOriginY; 195ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka } 196ff082d081f3ea18ff0b9b22126ee4a86504cf83cTadashi G. Takaoka} 197