Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2010 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 package com.android.internal.widget;
     18 
     19 import android.content.Context;
     20 import android.content.res.Resources;
     21 import android.content.res.XmlResourceParser;
     22 import android.graphics.drawable.Drawable;
     23 import android.inputmethodservice.Keyboard;
     24 import android.inputmethodservice.KeyboardView;
     25 import com.android.internal.R;
     26 
     27 /**
     28  * A basic, embed-able keyboard designed for password entry. Allows entry of all Latin-1 characters.
     29  *
     30  * It has two modes: alpha and numeric. In alpha mode, it allows all Latin-1 characters and enables
     31  * an additional keyboard with symbols.  In numeric mode, it shows a 12-key DTMF dialer-like
     32  * keypad with alpha characters hints.
     33  */
     34 public class PasswordEntryKeyboard extends Keyboard {
     35     private static final int SHIFT_OFF = 0;
     36     private static final int SHIFT_ON = 1;
     37     private static final int SHIFT_LOCKED = 2;
     38     public static final int KEYCODE_SPACE = ' ';
     39 
     40     private Drawable mShiftIcon;
     41     private Drawable mShiftLockIcon;
     42 
     43     // These two arrays must be the same length
     44     private Drawable[] mOldShiftIcons = { null, null };
     45     private Key[] mShiftKeys = { null, null };
     46 
     47     private Key mEnterKey;
     48     private Key mF1Key;
     49     private Key mSpaceKey;
     50     private int mShiftState = SHIFT_OFF;
     51 
     52     static int sSpacebarVerticalCorrection;
     53 
     54     public PasswordEntryKeyboard(Context context, int xmlLayoutResId) {
     55         this(context, xmlLayoutResId, 0);
     56     }
     57 
     58     public PasswordEntryKeyboard(Context context, int xmlLayoutResId, int width, int height) {
     59         this(context, xmlLayoutResId, 0, width, height);
     60     }
     61 
     62     public PasswordEntryKeyboard(Context context, int xmlLayoutResId, int mode) {
     63         super(context, xmlLayoutResId, mode);
     64         init(context);
     65     }
     66 
     67     public PasswordEntryKeyboard(Context context, int xmlLayoutResId, int mode,
     68             int width, int height) {
     69         super(context, xmlLayoutResId, mode, width, height);
     70         init(context);
     71     }
     72 
     73     private void init(Context context) {
     74         final Resources res = context.getResources();
     75         mShiftIcon = context.getDrawable(R.drawable.sym_keyboard_shift);
     76         mShiftLockIcon = context.getDrawable(R.drawable.sym_keyboard_shift_locked);
     77         sSpacebarVerticalCorrection = res.getDimensionPixelOffset(
     78                 R.dimen.password_keyboard_spacebar_vertical_correction);
     79     }
     80 
     81     public PasswordEntryKeyboard(Context context, int layoutTemplateResId,
     82             CharSequence characters, int columns, int horizontalPadding) {
     83         super(context, layoutTemplateResId, characters, columns, horizontalPadding);
     84     }
     85 
     86     @Override
     87     protected Key createKeyFromXml(Resources res, Row parent, int x, int y,
     88             XmlResourceParser parser) {
     89         LatinKey key = new LatinKey(res, parent, x, y, parser);
     90         final int code = key.codes[0];
     91         if (code >=0 && code != '\n' && (code < 32 || code > 127)) {
     92             // Log.w(TAG, "Key code for " + key.label + " is not latin-1");
     93             key.label = " ";
     94             key.setEnabled(false);
     95         }
     96         switch (key.codes[0]) {
     97             case 10:
     98                 mEnterKey = key;
     99                 break;
    100             case PasswordEntryKeyboardView.KEYCODE_F1:
    101                 mF1Key = key;
    102                 break;
    103             case 32:
    104                 mSpaceKey = key;
    105                 break;
    106         }
    107         return key;
    108     }
    109 
    110     /**
    111      * Allows enter key resources to be overridden
    112      * @param res resources to grab given items from
    113      * @param previewId preview drawable shown on enter key
    114      * @param iconId normal drawable shown on enter key
    115      * @param labelId string shown on enter key
    116      */
    117     void setEnterKeyResources(Resources res, int previewId, int iconId, int labelId) {
    118         if (mEnterKey != null) {
    119             // Reset some of the rarely used attributes.
    120             mEnterKey.popupCharacters = null;
    121             mEnterKey.popupResId = 0;
    122             mEnterKey.text = null;
    123 
    124             mEnterKey.iconPreview = res.getDrawable(previewId);
    125             mEnterKey.icon = res.getDrawable(iconId);
    126             mEnterKey.label = res.getText(labelId);
    127 
    128             // Set the initial size of the preview icon
    129             if (mEnterKey.iconPreview != null) {
    130                 mEnterKey.iconPreview.setBounds(0, 0,
    131                         mEnterKey.iconPreview.getIntrinsicWidth(),
    132                         mEnterKey.iconPreview.getIntrinsicHeight());
    133             }
    134         }
    135     }
    136 
    137     /**
    138      * Allows shiftlock to be turned on.  See {@link #setShiftLocked(boolean)}
    139      *
    140      */
    141     void enableShiftLock() {
    142         int i = 0;
    143         for (int index : getShiftKeyIndices()) {
    144             if (index >= 0 && i < mShiftKeys.length) {
    145                 mShiftKeys[i] = getKeys().get(index);
    146                 if (mShiftKeys[i] instanceof LatinKey) {
    147                     ((LatinKey)mShiftKeys[i]).enableShiftLock();
    148                 }
    149                 mOldShiftIcons[i] = mShiftKeys[i].icon;
    150                 i++;
    151             }
    152         }
    153     }
    154 
    155     /**
    156      * Turn on shift lock. This turns on the LED for this key, if it has one.
    157      * It should be followed by a call to {@link KeyboardView#invalidateKey(int)}
    158      * or {@link KeyboardView#invalidateAllKeys()}
    159      *
    160      * @param shiftLocked
    161      */
    162     void setShiftLocked(boolean shiftLocked) {
    163         for (Key shiftKey : mShiftKeys) {
    164             if (shiftKey != null) {
    165                 shiftKey.on = shiftLocked;
    166                 shiftKey.icon = mShiftLockIcon;
    167             }
    168         }
    169         mShiftState = shiftLocked ? SHIFT_LOCKED : SHIFT_ON;
    170     }
    171 
    172     /**
    173      * Turn on shift mode. Sets shift mode and turns on icon for shift key.
    174      * It should be followed by a call to {@link KeyboardView#invalidateKey(int)}
    175      * or {@link KeyboardView#invalidateAllKeys()}
    176      *
    177      * @param shiftLocked
    178      */
    179     @Override
    180     public boolean setShifted(boolean shiftState) {
    181         boolean shiftChanged = false;
    182         if (shiftState == false) {
    183             shiftChanged = mShiftState != SHIFT_OFF;
    184             mShiftState = SHIFT_OFF;
    185         } else if (mShiftState == SHIFT_OFF) {
    186             shiftChanged = mShiftState == SHIFT_OFF;
    187             mShiftState = SHIFT_ON;
    188         }
    189         for (int i = 0; i < mShiftKeys.length; i++) {
    190             if (mShiftKeys[i] != null) {
    191                 if (shiftState == false) {
    192                     mShiftKeys[i].on = false;
    193                     mShiftKeys[i].icon = mOldShiftIcons[i];
    194                 } else if (mShiftState == SHIFT_OFF) {
    195                     mShiftKeys[i].on = false;
    196                     mShiftKeys[i].icon = mShiftIcon;
    197                 }
    198             } else {
    199                 // return super.setShifted(shiftState);
    200             }
    201         }
    202         return shiftChanged;
    203     }
    204 
    205     /**
    206      * Whether or not keyboard is shifted.
    207      * @return true if keyboard state is shifted.
    208      */
    209     @Override
    210     public boolean isShifted() {
    211         if (mShiftKeys[0] != null) {
    212             return mShiftState != SHIFT_OFF;
    213         } else {
    214             return super.isShifted();
    215         }
    216     }
    217 
    218     static class LatinKey extends Keyboard.Key {
    219         private boolean mShiftLockEnabled;
    220         private boolean mEnabled = true;
    221 
    222         public LatinKey(Resources res, Keyboard.Row parent, int x, int y,
    223                 XmlResourceParser parser) {
    224             super(res, parent, x, y, parser);
    225             if (popupCharacters != null && popupCharacters.length() == 0) {
    226                 // If there is a keyboard with no keys specified in popupCharacters
    227                 popupResId = 0;
    228             }
    229         }
    230 
    231         void setEnabled(boolean enabled) {
    232             mEnabled = enabled;
    233         }
    234 
    235         void enableShiftLock() {
    236             mShiftLockEnabled = true;
    237         }
    238 
    239         @Override
    240         public void onReleased(boolean inside) {
    241             if (!mShiftLockEnabled) {
    242                 super.onReleased(inside);
    243             } else {
    244                 pressed = !pressed;
    245             }
    246         }
    247 
    248         /**
    249          * Overriding this method so that we can reduce the target area for certain keys.
    250          */
    251         @Override
    252         public boolean isInside(int x, int y) {
    253             if (!mEnabled) {
    254                 return false;
    255             }
    256             final int code = codes[0];
    257             if (code == KEYCODE_SHIFT || code == KEYCODE_DELETE) {
    258                 y -= height / 10;
    259                 if (code == KEYCODE_SHIFT) x += width / 6;
    260                 if (code == KEYCODE_DELETE) x -= width / 6;
    261             } else if (code == KEYCODE_SPACE) {
    262                 y += PasswordEntryKeyboard.sSpacebarVerticalCorrection;
    263             }
    264             return super.isInside(x, y);
    265         }
    266     }
    267 }
    268