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