• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PasswordEntryKeyboard(Context context, int xmlLayoutResId)54     public PasswordEntryKeyboard(Context context, int xmlLayoutResId) {
55         this(context, xmlLayoutResId, 0);
56     }
57 
PasswordEntryKeyboard(Context context, int xmlLayoutResId, int width, int height)58     public PasswordEntryKeyboard(Context context, int xmlLayoutResId, int width, int height) {
59         this(context, xmlLayoutResId, 0, width, height);
60     }
61 
PasswordEntryKeyboard(Context context, int xmlLayoutResId, int mode)62     public PasswordEntryKeyboard(Context context, int xmlLayoutResId, int mode) {
63         super(context, xmlLayoutResId, mode);
64         init(context);
65     }
66 
PasswordEntryKeyboard(Context context, int xmlLayoutResId, int mode, int width, int height)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 
init(Context context)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 
PasswordEntryKeyboard(Context context, int layoutTemplateResId, CharSequence characters, int columns, int horizontalPadding)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
createKeyFromXml(Resources res, Row parent, int x, int y, XmlResourceParser parser)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      */
setEnterKeyResources(Resources res, int previewId, int iconId, int labelId)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      */
enableShiftLock()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      */
setShiftLocked(boolean shiftLocked)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
setShifted(boolean shiftState)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
isShifted()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 
LatinKey(Resources res, Keyboard.Row parent, int x, int y, XmlResourceParser parser)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 
setEnabled(boolean enabled)231         void setEnabled(boolean enabled) {
232             mEnabled = enabled;
233         }
234 
enableShiftLock()235         void enableShiftLock() {
236             mShiftLockEnabled = true;
237         }
238 
239         @Override
onReleased(boolean inside)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
isInside(int x, int y)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