/* * 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 android.content.Context; import android.content.res.Resources; import android.inputmethodservice.Keyboard; import android.inputmethodservice.KeyboardView; import android.inputmethodservice.KeyboardView.OnKeyboardActionListener; import android.os.Handler; import android.os.SystemClock; import android.os.Vibrator; import android.provider.Settings; import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewRootImpl; import com.android.internal.R; public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener { public static final int KEYBOARD_MODE_ALPHA = 0; public static final int KEYBOARD_MODE_NUMERIC = 1; private static final int KEYBOARD_STATE_NORMAL = 0; private static final int KEYBOARD_STATE_SHIFTED = 1; private static final int KEYBOARD_STATE_CAPSLOCK = 2; private static final String TAG = "PasswordEntryKeyboardHelper"; private int mKeyboardMode = KEYBOARD_MODE_ALPHA; private int mKeyboardState = KEYBOARD_STATE_NORMAL; private PasswordEntryKeyboard mQwertyKeyboard; private PasswordEntryKeyboard mQwertyKeyboardShifted; private PasswordEntryKeyboard mSymbolsKeyboard; private PasswordEntryKeyboard mSymbolsKeyboardShifted; private PasswordEntryKeyboard mNumericKeyboard; private final Context mContext; private final View mTargetView; private final KeyboardView mKeyboardView; private long[] mVibratePattern; private boolean mEnableHaptics = false; private static final int NUMERIC = 0; private static final int QWERTY = 1; private static final int QWERTY_SHIFTED = 2; private static final int SYMBOLS = 3; private static final int SYMBOLS_SHIFTED = 4; int mLayouts[] = new int[] { R.xml.password_kbd_numeric, R.xml.password_kbd_qwerty, R.xml.password_kbd_qwerty_shifted, R.xml.password_kbd_symbols, R.xml.password_kbd_symbols_shift }; private boolean mUsingScreenWidth; public PasswordEntryKeyboardHelper(Context context, KeyboardView keyboardView, View targetView) { this(context, keyboardView, targetView, true, null); } public PasswordEntryKeyboardHelper(Context context, KeyboardView keyboardView, View targetView, boolean useFullScreenWidth) { this(context, keyboardView, targetView, useFullScreenWidth, null); } public PasswordEntryKeyboardHelper(Context context, KeyboardView keyboardView, View targetView, boolean useFullScreenWidth, int layouts[]) { mContext = context; mTargetView = targetView; mKeyboardView = keyboardView; mKeyboardView.setOnKeyboardActionListener(this); mUsingScreenWidth = useFullScreenWidth; if (layouts != null) { if (layouts.length != mLayouts.length) { throw new RuntimeException("Wrong number of layouts"); } for (int i = 0; i < mLayouts.length; i++) { mLayouts[i] = layouts[i]; } } createKeyboards(); } public void createKeyboards() { LayoutParams lp = mKeyboardView.getLayoutParams(); if (mUsingScreenWidth || lp.width == ViewGroup.LayoutParams.MATCH_PARENT) { createKeyboardsWithDefaultWidth(); } else { createKeyboardsWithSpecificSize(lp.width, lp.height); } } public void setEnableHaptics(boolean enabled) { mEnableHaptics = enabled; } public boolean isAlpha() { return mKeyboardMode == KEYBOARD_MODE_ALPHA; } private void createKeyboardsWithSpecificSize(int width, int height) { mNumericKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[NUMERIC], width, height); mQwertyKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[QWERTY], R.id.mode_normal, width, height); mQwertyKeyboard.enableShiftLock(); mQwertyKeyboardShifted = new PasswordEntryKeyboard(mContext, mLayouts[QWERTY_SHIFTED], R.id.mode_normal, width, height); mQwertyKeyboardShifted.enableShiftLock(); mQwertyKeyboardShifted.setShifted(true); // always shifted. mSymbolsKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[SYMBOLS], width, height); mSymbolsKeyboard.enableShiftLock(); mSymbolsKeyboardShifted = new PasswordEntryKeyboard(mContext, mLayouts[SYMBOLS_SHIFTED], width, height); mSymbolsKeyboardShifted.enableShiftLock(); mSymbolsKeyboardShifted.setShifted(true); // always shifted } private void createKeyboardsWithDefaultWidth() { mNumericKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[NUMERIC]); mQwertyKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[QWERTY], R.id.mode_normal); mQwertyKeyboard.enableShiftLock(); mQwertyKeyboardShifted = new PasswordEntryKeyboard(mContext, mLayouts[QWERTY_SHIFTED], R.id.mode_normal); mQwertyKeyboardShifted.enableShiftLock(); mQwertyKeyboardShifted.setShifted(true); // always shifted. mSymbolsKeyboard = new PasswordEntryKeyboard(mContext, mLayouts[SYMBOLS]); mSymbolsKeyboard.enableShiftLock(); mSymbolsKeyboardShifted = new PasswordEntryKeyboard(mContext, mLayouts[SYMBOLS_SHIFTED]); mSymbolsKeyboardShifted.enableShiftLock(); mSymbolsKeyboardShifted.setShifted(true); // always shifted } public void setKeyboardMode(int mode) { switch (mode) { case KEYBOARD_MODE_ALPHA: mKeyboardView.setKeyboard(mQwertyKeyboard); mKeyboardState = KEYBOARD_STATE_NORMAL; final boolean visiblePassword = Settings.System.getInt( mContext.getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, 1) != 0; final boolean enablePreview = false; // TODO: grab from configuration mKeyboardView.setPreviewEnabled(visiblePassword && enablePreview); break; case KEYBOARD_MODE_NUMERIC: mKeyboardView.setKeyboard(mNumericKeyboard); mKeyboardState = KEYBOARD_STATE_NORMAL; mKeyboardView.setPreviewEnabled(false); // never show popup for numeric keypad break; } mKeyboardMode = mode; } private void sendKeyEventsToTarget(int character) { ViewRootImpl viewRootImpl = mTargetView.getViewRootImpl(); KeyEvent[] events = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD).getEvents( new char[] { (char) character }); if (events != null) { final int N = events.length; for (int i=0; i