diff options
author | Jim Miller <jaggies@google.com> | 2010-02-05 18:51:59 -0800 |
---|---|---|
committer | Jim Miller <jaggies@google.com> | 2010-02-08 21:04:39 -0800 |
commit | 0b31970cac04259a6e20dfc6d6e42cd9532528e3 (patch) | |
tree | b668af11dd498b3c23888746a167f6af321ce859 /core/java/com/android/internal/widget/PasswordEntryKeyboard.java | |
parent | 628fd6d9c11ed9806abebf34bc986247c106328f (diff) | |
download | frameworks_base-0b31970cac04259a6e20dfc6d6e42cd9532528e3.zip frameworks_base-0b31970cac04259a6e20dfc6d6e42cd9532528e3.tar.gz frameworks_base-0b31970cac04259a6e20dfc6d6e42cd9532528e3.tar.bz2 |
Fix 2402303: Split Keyboard widget from LatinIME into reusable PasswordEntryKeyboardView
- Added new PasswordEntryKeyboardView to internal/widgets. Widget supports:
- alpha mode with symbols (latin-1 only).
- a numeric keyboard
- IME emulation that applies keyboard input to arbitrary top-level view widget.
- Added new transparent assets to framework resources.
- Modified Keyguard and Keyguard layouts to use new PasswordEntryKeyboardView.
Diffstat (limited to 'core/java/com/android/internal/widget/PasswordEntryKeyboard.java')
-rw-r--r-- | core/java/com/android/internal/widget/PasswordEntryKeyboard.java | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboard.java b/core/java/com/android/internal/widget/PasswordEntryKeyboard.java new file mode 100644 index 0000000..51f7f69 --- /dev/null +++ b/core/java/com/android/internal/widget/PasswordEntryKeyboard.java @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.internal.widget; + +import java.util.Locale; +import android.content.Context; +import android.content.res.Resources; +import android.content.res.XmlResourceParser; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.Paint.Align; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.inputmethodservice.Keyboard; +import android.inputmethodservice.KeyboardView; +import android.util.Log; +import com.android.internal.R; + +/** + * A basic, embed-able keyboard designed for password entry. Allows entry of all Latin-1 characters. + * + * It has two modes: alpha and numeric. In alpha mode, it allows all Latin-1 characters and enables + * an additional keyboard with symbols. In numeric mode, it shows a 12-key DTMF dialer-like + * keypad with alpha characters hints. + */ +public class PasswordEntryKeyboard extends Keyboard { + private static final String TAG = "PasswordEntryKeyboard"; + private static final int SHIFT_OFF = 0; + private static final int SHIFT_ON = 1; + private static final int SHIFT_LOCKED = 2; + public static final int KEYCODE_SPACE = ' '; + + private Drawable mShiftIcon; + private Drawable mShiftLockIcon; + private Drawable mShiftLockPreviewIcon; + private Drawable mOldShiftIcon; + private Drawable mOldShiftPreviewIcon; + private Drawable mSpaceIcon; + private Key mShiftKey; + private Key mEnterKey; + private Key mF1Key; + private Key mSpaceKey; + private Locale mLocale; + private Resources mRes; + private int mExtensionResId; + private int mShiftState = SHIFT_OFF; + + static int sSpacebarVerticalCorrection; + + public PasswordEntryKeyboard(Context context, int xmlLayoutResId) { + this(context, xmlLayoutResId, 0); + } + + public PasswordEntryKeyboard(Context context, int xmlLayoutResId, int mode) { + super(context, xmlLayoutResId, mode); + final Resources res = context.getResources(); + mRes = res; + mShiftIcon = res.getDrawable(R.drawable.sym_keyboard_shift); + mShiftLockIcon = res.getDrawable(R.drawable.sym_keyboard_shift_locked); + mShiftLockPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_shift_locked); + mShiftLockPreviewIcon.setBounds(0, 0, + mShiftLockPreviewIcon.getIntrinsicWidth(), + mShiftLockPreviewIcon.getIntrinsicHeight()); + mSpaceIcon = res.getDrawable(R.drawable.sym_keyboard_space); + sSpacebarVerticalCorrection = res.getDimensionPixelOffset( + R.dimen.password_keyboard_spacebar_vertical_correction); + } + + public PasswordEntryKeyboard(Context context, int layoutTemplateResId, + CharSequence characters, int columns, int horizontalPadding) { + super(context, layoutTemplateResId, characters, columns, horizontalPadding); + } + + @Override + protected Key createKeyFromXml(Resources res, Row parent, int x, int y, + XmlResourceParser parser) { + LatinKey key = new LatinKey(res, parent, x, y, parser); + final int code = key.codes[0]; + if (code >=0 && code != '\n' && (code < 32 || code > 127)) { + Log.w(TAG, "Key code for " + key.label + " is not latin-1"); + key.label = " "; + key.setEnabled(false); + } + switch (key.codes[0]) { + case 10: + mEnterKey = key; + break; + case PasswordEntryKeyboardView.KEYCODE_F1: + mF1Key = key; + break; + case 32: + mSpaceKey = key; + break; + } + return key; + } + + /** + * Allows enter key resources to be overridden + * @param res resources to grab given items from + * @param previewId preview drawable shown on enter key + * @param iconId normal drawable shown on enter key + * @param labelId string shown on enter key + */ + void setEnterKeyResources(Resources res, int previewId, int iconId, int labelId) { + if (mEnterKey != null) { + // Reset some of the rarely used attributes. + mEnterKey.popupCharacters = null; + mEnterKey.popupResId = 0; + mEnterKey.text = null; + + mEnterKey.iconPreview = res.getDrawable(previewId); + mEnterKey.icon = res.getDrawable(iconId); + mEnterKey.label = res.getText(labelId); + + // Set the initial size of the preview icon + if (mEnterKey.iconPreview != null) { + mEnterKey.iconPreview.setBounds(0, 0, + mEnterKey.iconPreview.getIntrinsicWidth(), + mEnterKey.iconPreview.getIntrinsicHeight()); + } + } + } + + /** + * Allows shiftlock to be turned on. See {@link #setShiftLocked(boolean)} + * + */ + void enableShiftLock() { + int index = getShiftKeyIndex(); + if (index >= 0) { + mShiftKey = getKeys().get(index); + if (mShiftKey instanceof LatinKey) { + ((LatinKey)mShiftKey).enableShiftLock(); + } + mOldShiftIcon = mShiftKey.icon; + mOldShiftPreviewIcon = mShiftKey.iconPreview; + } + } + + /** + * Turn on shift lock. This turns on the LED for this key, if it has one. + * It should be followed by a call to {@link KeyboardView#invalidateKey(int)} + * or {@link KeyboardView#invalidateAllKeys()} + * + * @param shiftLocked + */ + void setShiftLocked(boolean shiftLocked) { + if (mShiftKey != null) { + if (shiftLocked) { + mShiftKey.on = true; + mShiftKey.icon = mShiftLockIcon; + mShiftState = SHIFT_LOCKED; + } else { + mShiftKey.on = false; + mShiftKey.icon = mShiftLockIcon; + mShiftState = SHIFT_ON; + } + } + } + + /** + * Turn on shift mode. Sets shift mode and turns on icon for shift key. + * It should be followed by a call to {@link KeyboardView#invalidateKey(int)} + * or {@link KeyboardView#invalidateAllKeys()} + * + * @param shiftLocked + */ + @Override + public boolean setShifted(boolean shiftState) { + boolean shiftChanged = false; + if (mShiftKey != null) { + if (shiftState == false) { + shiftChanged = mShiftState != SHIFT_OFF; + mShiftState = SHIFT_OFF; + mShiftKey.on = false; + mShiftKey.icon = mOldShiftIcon; + } else if (mShiftState == SHIFT_OFF) { + shiftChanged = mShiftState == SHIFT_OFF; + mShiftState = SHIFT_ON; + mShiftKey.on = false; + mShiftKey.icon = mShiftIcon; + } + } else { + return super.setShifted(shiftState); + } + return shiftChanged; + } + + /** + * Whether or not keyboard is shifted. + * @return true if keyboard state is shifted. + */ + @Override + public boolean isShifted() { + if (mShiftKey != null) { + return mShiftState != SHIFT_OFF; + } else { + return super.isShifted(); + } + } + + /** + * Sets keyboard extension. Keyboard extension is shown when input is detected above keyboard + * while keyboard has focus. + * + * @param resId + */ + public void setExtension(int resId) { + mExtensionResId = resId; + } + + /** + * Get current extesion resource id. + * + * @return resource id, 0 if not set. + */ + public int getExtension() { + return mExtensionResId; + } + + private void updateSpaceBarForLocale() { + if (mLocale != null) { + // Create the graphic for spacebar + Bitmap buffer = Bitmap.createBitmap(mSpaceKey.width, mSpaceIcon.getIntrinsicHeight(), + Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(buffer); + canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); + Paint paint = new Paint(); + paint.setAntiAlias(true); + // TODO: Make the text size a customizable attribute + paint.setTextSize(22); + paint.setTextAlign(Align.CENTER); + // Draw a drop shadow for the text + paint.setShadowLayer(1f, 0, 0, 0xFF000000); + paint.setColor(0x80C0C0C0); + canvas.drawText(mLocale.getDisplayLanguage(mLocale), + buffer.getWidth() / 2, - paint.ascent() + 2, paint); + int x = (buffer.getWidth() - mSpaceIcon.getIntrinsicWidth()) / 2; + int y = buffer.getHeight() - mSpaceIcon.getIntrinsicHeight(); + mSpaceIcon.setBounds(x, y, + x + mSpaceIcon.getIntrinsicWidth(), y + mSpaceIcon.getIntrinsicHeight()); + mSpaceIcon.draw(canvas); + mSpaceKey.icon = new BitmapDrawable(mRes, buffer); + mSpaceKey.repeatable = false; + } else { + mSpaceKey.icon = mRes.getDrawable(R.drawable.sym_keyboard_space); + mSpaceKey.repeatable = true; + } + } + + public void setLanguage(Locale locale) { + if (mLocale != null && mLocale.equals(locale)) return; + mLocale = locale; + updateSpaceBarForLocale(); + } + + static class LatinKey extends Keyboard.Key { + private boolean mShiftLockEnabled; + private boolean mEnabled = true; + + public LatinKey(Resources res, Keyboard.Row parent, int x, int y, + XmlResourceParser parser) { + super(res, parent, x, y, parser); + if (popupCharacters != null && popupCharacters.length() == 0) { + // If there is a keyboard with no keys specified in popupCharacters + popupResId = 0; + } + } + + void setEnabled(boolean enabled) { + mEnabled = enabled; + } + + void enableShiftLock() { + mShiftLockEnabled = true; + } + + @Override + public void onReleased(boolean inside) { + if (!mShiftLockEnabled) { + super.onReleased(inside); + } else { + pressed = !pressed; + } + } + + /** + * Overriding this method so that we can reduce the target area for certain keys. + */ + @Override + public boolean isInside(int x, int y) { + if (!mEnabled) { + return false; + } + final int code = codes[0]; + if (code == KEYCODE_SHIFT || code == KEYCODE_DELETE) { + y -= height / 10; + if (code == KEYCODE_SHIFT) x += width / 6; + if (code == KEYCODE_DELETE) x -= width / 6; + } else if (code == KEYCODE_SPACE) { + y += PasswordEntryKeyboard.sSpacebarVerticalCorrection; + } + return super.isInside(x, y); + } + } +} |