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