10b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller/*
20b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller * Copyright (C) 2010 Google Inc.
30b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller *
40b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller * Licensed under the Apache License, Version 2.0 (the "License"); you may not
50b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller * use this file except in compliance with the License. You may obtain a copy of
60b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller * the License at
70b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller *
80b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller * http://www.apache.org/licenses/LICENSE-2.0
90b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller *
100b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller * Unless required by applicable law or agreed to in writing, software
110b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
120b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
130b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller * License for the specific language governing permissions and limitations under
140b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller * the License.
150b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller */
160b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
170b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Millerpackage com.android.internal.widget;
180b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
190b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Millerimport java.util.Locale;
200b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Millerimport android.content.Context;
210b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Millerimport android.content.res.Resources;
220b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Millerimport android.content.res.XmlResourceParser;
230b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Millerimport android.graphics.drawable.Drawable;
240b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Millerimport android.inputmethodservice.Keyboard;
250b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Millerimport android.inputmethodservice.KeyboardView;
260b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Millerimport com.android.internal.R;
270b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
280b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller/**
290b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller * A basic, embed-able keyboard designed for password entry. Allows entry of all Latin-1 characters.
300b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller *
310b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller * It has two modes: alpha and numeric. In alpha mode, it allows all Latin-1 characters and enables
320b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller * an additional keyboard with symbols.  In numeric mode, it shows a 12-key DTMF dialer-like
330b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller * keypad with alpha characters hints.
340b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller */
350b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Millerpublic class PasswordEntryKeyboard extends Keyboard {
360b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    private static final int SHIFT_OFF = 0;
370b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    private static final int SHIFT_ON = 1;
380b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    private static final int SHIFT_LOCKED = 2;
390b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    public static final int KEYCODE_SPACE = ' ';
400b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
410b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    private Drawable mShiftIcon;
420b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    private Drawable mShiftLockIcon;
436465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller
446465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller    // These two arrays must be the same length
456465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller    private Drawable[] mOldShiftIcons = { null, null };
466465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller    private Key[] mShiftKeys = { null, null };
476465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller
480b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    private Key mEnterKey;
490b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    private Key mF1Key;
500b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    private Key mSpaceKey;
510b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    private int mShiftState = SHIFT_OFF;
520b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
530b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    static int sSpacebarVerticalCorrection;
540b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
550b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    public PasswordEntryKeyboard(Context context, int xmlLayoutResId) {
560b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        this(context, xmlLayoutResId, 0);
570b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    }
580b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
598171b5182f5f07d33c9dfdf2dd8f0f6ae9588039Jae Yong Sung    public PasswordEntryKeyboard(Context context, int xmlLayoutResId, int width, int height) {
608171b5182f5f07d33c9dfdf2dd8f0f6ae9588039Jae Yong Sung        this(context, xmlLayoutResId, 0, width, height);
618171b5182f5f07d33c9dfdf2dd8f0f6ae9588039Jae Yong Sung    }
628171b5182f5f07d33c9dfdf2dd8f0f6ae9588039Jae Yong Sung
630b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    public PasswordEntryKeyboard(Context context, int xmlLayoutResId, int mode) {
640b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        super(context, xmlLayoutResId, mode);
658171b5182f5f07d33c9dfdf2dd8f0f6ae9588039Jae Yong Sung        init(context);
668171b5182f5f07d33c9dfdf2dd8f0f6ae9588039Jae Yong Sung    }
678171b5182f5f07d33c9dfdf2dd8f0f6ae9588039Jae Yong Sung
688171b5182f5f07d33c9dfdf2dd8f0f6ae9588039Jae Yong Sung    public PasswordEntryKeyboard(Context context, int xmlLayoutResId, int mode,
698171b5182f5f07d33c9dfdf2dd8f0f6ae9588039Jae Yong Sung            int width, int height) {
708171b5182f5f07d33c9dfdf2dd8f0f6ae9588039Jae Yong Sung        super(context, xmlLayoutResId, mode, width, height);
718171b5182f5f07d33c9dfdf2dd8f0f6ae9588039Jae Yong Sung        init(context);
728171b5182f5f07d33c9dfdf2dd8f0f6ae9588039Jae Yong Sung    }
738171b5182f5f07d33c9dfdf2dd8f0f6ae9588039Jae Yong Sung
748171b5182f5f07d33c9dfdf2dd8f0f6ae9588039Jae Yong Sung    private void init(Context context) {
750b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        final Resources res = context.getResources();
760b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        mShiftIcon = res.getDrawable(R.drawable.sym_keyboard_shift);
770b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        mShiftLockIcon = res.getDrawable(R.drawable.sym_keyboard_shift_locked);
780b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        sSpacebarVerticalCorrection = res.getDimensionPixelOffset(
790b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                R.dimen.password_keyboard_spacebar_vertical_correction);
800b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    }
810b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
820b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    public PasswordEntryKeyboard(Context context, int layoutTemplateResId,
830b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            CharSequence characters, int columns, int horizontalPadding) {
840b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        super(context, layoutTemplateResId, characters, columns, horizontalPadding);
850b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    }
860b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
870b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    @Override
880b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    protected Key createKeyFromXml(Resources res, Row parent, int x, int y,
890b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            XmlResourceParser parser) {
900b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        LatinKey key = new LatinKey(res, parent, x, y, parser);
910b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        final int code = key.codes[0];
920b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        if (code >=0 && code != '\n' && (code < 32 || code > 127)) {
93ec52eedc2ceb623b503f6b82eb560c0e9a6e4619Jim Miller            // Log.w(TAG, "Key code for " + key.label + " is not latin-1");
940b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            key.label = " ";
950b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            key.setEnabled(false);
960b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        }
970b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        switch (key.codes[0]) {
980b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            case 10:
990b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                mEnterKey = key;
1000b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                break;
1010b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            case PasswordEntryKeyboardView.KEYCODE_F1:
1020b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                mF1Key = key;
1030b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                break;
1040b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            case 32:
1050b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                mSpaceKey = key;
1060b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                break;
1070b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        }
1080b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        return key;
1090b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    }
1100b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
1110b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    /**
1120b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * Allows enter key resources to be overridden
1130b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * @param res resources to grab given items from
1140b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * @param previewId preview drawable shown on enter key
1150b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * @param iconId normal drawable shown on enter key
1160b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * @param labelId string shown on enter key
1170b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     */
1180b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    void setEnterKeyResources(Resources res, int previewId, int iconId, int labelId) {
1190b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        if (mEnterKey != null) {
1200b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            // Reset some of the rarely used attributes.
1210b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            mEnterKey.popupCharacters = null;
1220b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            mEnterKey.popupResId = 0;
1230b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            mEnterKey.text = null;
1240b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
1250b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            mEnterKey.iconPreview = res.getDrawable(previewId);
1260b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            mEnterKey.icon = res.getDrawable(iconId);
1270b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            mEnterKey.label = res.getText(labelId);
1280b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
1290b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            // Set the initial size of the preview icon
1300b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            if (mEnterKey.iconPreview != null) {
1310b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                mEnterKey.iconPreview.setBounds(0, 0,
1320b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                        mEnterKey.iconPreview.getIntrinsicWidth(),
1330b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                        mEnterKey.iconPreview.getIntrinsicHeight());
1340b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            }
1350b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        }
1360b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    }
1370b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
1380b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    /**
1390b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * Allows shiftlock to be turned on.  See {@link #setShiftLocked(boolean)}
1400b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     *
1410b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     */
1420b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    void enableShiftLock() {
1436465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller        int i = 0;
1446465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller        for (int index : getShiftKeyIndices()) {
1456465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller            if (index >= 0 && i < mShiftKeys.length) {
1466465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                mShiftKeys[i] = getKeys().get(index);
1476465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                if (mShiftKeys[i] instanceof LatinKey) {
1486465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                    ((LatinKey)mShiftKeys[i]).enableShiftLock();
1496465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                }
1506465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                mOldShiftIcons[i] = mShiftKeys[i].icon;
1516465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                i++;
1520b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            }
1530b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        }
1540b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    }
1550b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
1560b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    /**
1570b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * Turn on shift lock. This turns on the LED for this key, if it has one.
1580b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * It should be followed by a call to {@link KeyboardView#invalidateKey(int)}
1590b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * or {@link KeyboardView#invalidateAllKeys()}
1600b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     *
1610b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * @param shiftLocked
1620b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     */
1630b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    void setShiftLocked(boolean shiftLocked) {
1646465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller        for (Key shiftKey : mShiftKeys) {
1656465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller            if (shiftKey != null) {
1666465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                shiftKey.on = shiftLocked;
1676465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                shiftKey.icon = mShiftLockIcon;
1680b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            }
1690b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        }
1706465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller        mShiftState = shiftLocked ? SHIFT_LOCKED : SHIFT_ON;
1710b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    }
1720b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
1730b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    /**
1740b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * Turn on shift mode. Sets shift mode and turns on icon for shift key.
1750b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * It should be followed by a call to {@link KeyboardView#invalidateKey(int)}
1760b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * or {@link KeyboardView#invalidateAllKeys()}
1770b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     *
1780b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * @param shiftLocked
1790b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     */
1800b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    @Override
1810b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    public boolean setShifted(boolean shiftState) {
1820b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        boolean shiftChanged = false;
1836465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller        if (shiftState == false) {
1846465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller            shiftChanged = mShiftState != SHIFT_OFF;
1856465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller            mShiftState = SHIFT_OFF;
1866465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller        } else if (mShiftState == SHIFT_OFF) {
1876465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller            shiftChanged = mShiftState == SHIFT_OFF;
1886465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller            mShiftState = SHIFT_ON;
1896465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller        }
1906465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller        for (int i = 0; i < mShiftKeys.length; i++) {
1916465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller            if (mShiftKeys[i] != null) {
1926465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                if (shiftState == false) {
1936465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                    mShiftKeys[i].on = false;
1946465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                    mShiftKeys[i].icon = mOldShiftIcons[i];
1956465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                } else if (mShiftState == SHIFT_OFF) {
1966465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                    mShiftKeys[i].on = false;
1976465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                    mShiftKeys[i].icon = mShiftIcon;
1986465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                }
1996465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller            } else {
2006465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller                // return super.setShifted(shiftState);
2010b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            }
2020b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        }
2030b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        return shiftChanged;
2040b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    }
2050b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
2060b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    /**
2070b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * Whether or not keyboard is shifted.
2080b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     * @return true if keyboard state is shifted.
2090b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller     */
2100b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    @Override
2110b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    public boolean isShifted() {
2126465f7753783a614948fb3ffbd8c072345b4eea1Jim Miller        if (mShiftKeys[0] != null) {
2130b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            return mShiftState != SHIFT_OFF;
2140b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        } else {
2150b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            return super.isShifted();
2160b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        }
2170b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    }
2180b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
2190b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    static class LatinKey extends Keyboard.Key {
2200b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        private boolean mShiftLockEnabled;
2210b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        private boolean mEnabled = true;
2220b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
2230b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        public LatinKey(Resources res, Keyboard.Row parent, int x, int y,
2240b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                XmlResourceParser parser) {
2250b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            super(res, parent, x, y, parser);
2260b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            if (popupCharacters != null && popupCharacters.length() == 0) {
2270b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                // If there is a keyboard with no keys specified in popupCharacters
2280b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                popupResId = 0;
2290b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            }
2300b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        }
2310b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
2320b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        void setEnabled(boolean enabled) {
2330b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            mEnabled = enabled;
2340b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        }
2350b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
2360b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        void enableShiftLock() {
2370b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            mShiftLockEnabled = true;
2380b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        }
2390b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
2400b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        @Override
2410b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        public void onReleased(boolean inside) {
2420b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            if (!mShiftLockEnabled) {
2430b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                super.onReleased(inside);
2440b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            } else {
2450b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                pressed = !pressed;
2460b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            }
2470b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        }
2480b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller
2490b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        /**
2500b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller         * Overriding this method so that we can reduce the target area for certain keys.
2510b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller         */
2520b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        @Override
2530b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        public boolean isInside(int x, int y) {
2540b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            if (!mEnabled) {
2550b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                return false;
2560b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            }
2570b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            final int code = codes[0];
2580b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            if (code == KEYCODE_SHIFT || code == KEYCODE_DELETE) {
2590b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                y -= height / 10;
2600b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                if (code == KEYCODE_SHIFT) x += width / 6;
2610b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                if (code == KEYCODE_DELETE) x -= width / 6;
2620b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            } else if (code == KEYCODE_SPACE) {
2630b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller                y += PasswordEntryKeyboard.sSpacebarVerticalCorrection;
2640b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            }
2650b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller            return super.isInside(x, y);
2660b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller        }
2670b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller    }
2680b31970cac04259a6e20dfc6d6e42cd9532528e3Jim Miller}
269