KeyguardSimPukView.java revision 3af630c8d18bcf4b23a5a308917319dd04cc8ed2
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.internal.policy.impl.keyguard;
17
18import android.app.Activity;
19import android.app.Dialog;
20import android.app.ProgressDialog;
21import android.content.Context;
22import android.content.res.Configuration;
23import android.graphics.Rect;
24import android.os.RemoteException;
25import android.os.ServiceManager;
26import android.text.Editable;
27import android.util.AttributeSet;
28import android.util.Log;
29import android.view.KeyEvent;
30import android.view.MotionEvent;
31import android.view.View;
32import android.view.WindowManager;
33import android.view.inputmethod.EditorInfo;
34import android.widget.LinearLayout;
35import android.widget.TextView;
36import android.widget.TextView.OnEditorActionListener;
37
38import com.android.internal.telephony.ITelephony;
39import com.android.internal.widget.LockPatternUtils;
40import com.android.internal.widget.PasswordEntryKeyboardHelper;
41import com.android.internal.widget.PasswordEntryKeyboardView;
42import com.android.internal.R;
43
44public class KeyguardSimPukView extends LinearLayout implements View.OnClickListener,
45    View.OnFocusChangeListener, KeyguardSecurityView, OnEditorActionListener {
46
47    private static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
48
49    private TextView mPukText;
50    private TextView mPinText;
51    private TextView mFocusedEntry;
52
53    private View mDelPukButton;
54    private View mDelPinButton;
55
56    private ProgressDialog mSimUnlockProgressDialog = null;
57    private KeyguardSecurityCallback mCallback;
58
59    private KeyguardNavigationManager mNavigationManager;
60
61    private PasswordEntryKeyboardView mKeyboardView;
62
63    private PasswordEntryKeyboardHelper mKeyboardHelper;
64
65    private LockPatternUtils mLockPatternUtils;
66
67    private volatile boolean mCheckInProgress;
68
69    public KeyguardSimPukView(Context context) {
70        this(context, null);
71    }
72
73    public KeyguardSimPukView(Context context, AttributeSet attrs) {
74        super(context, attrs);
75        mLockPatternUtils = new LockPatternUtils(getContext());
76    }
77
78    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
79        mCallback = callback;
80        mLockPatternUtils = new LockPatternUtils(getContext());
81    }
82
83    @Override
84    protected void onFinishInflate() {
85        super.onFinishInflate();
86
87        mNavigationManager = new KeyguardNavigationManager(this);
88
89        mPukText = (TextView) findViewById(R.id.sim_puk_entry);
90        mPukText.setOnEditorActionListener(this);
91        mPinText = (TextView) findViewById(R.id.sim_pin_entry);
92        mPinText.setOnEditorActionListener(this);
93        mDelPukButton = findViewById(R.id.puk_delete_button);
94        mDelPukButton.setOnClickListener(this);
95        mDelPinButton = findViewById(R.id.pin_delete_button);
96        mDelPinButton.setOnClickListener(this);
97
98        mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
99        mKeyboardHelper = new PasswordEntryKeyboardHelper(mContext, mKeyboardView, this, false,
100                new int[] {
101                R.xml.kg_password_kbd_numeric,
102                com.android.internal.R.xml.password_kbd_qwerty,
103                com.android.internal.R.xml.password_kbd_qwerty_shifted,
104                com.android.internal.R.xml.password_kbd_symbols,
105                com.android.internal.R.xml.password_kbd_symbols_shift
106                });
107        mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
108        mKeyboardHelper.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled());
109
110        mNavigationManager.setMessage(R.string.kg_sim_puk_recovery_hint);
111
112        mPinText.setFocusableInTouchMode(true);
113        mPinText.setOnFocusChangeListener(this);
114        mPukText.setFocusableInTouchMode(true);
115        mPukText.setOnFocusChangeListener(this);
116
117        setFocusableInTouchMode(true);
118
119        reset();
120    }
121
122    @Override
123    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
124        return mPukText.requestFocus(direction, previouslyFocusedRect);
125    }
126
127    public boolean needsInput() {
128        return false; // This view provides its own keypad
129    }
130
131    public void onPause() {
132
133    }
134
135    public void onResume() {
136        reset();
137    }
138
139    /** {@inheritDoc} */
140    public void cleanUp() {
141        // dismiss the dialog.
142        if (mSimUnlockProgressDialog != null) {
143            mSimUnlockProgressDialog.dismiss();
144            mSimUnlockProgressDialog = null;
145        }
146    }
147
148    /**
149     * Since the IPC can block, we want to run the request in a separate thread
150     * with a callback.
151     */
152    private abstract class CheckSimPuk extends Thread {
153
154        private final String mPin, mPuk;
155
156        protected CheckSimPuk(String puk, String pin) {
157            mPuk = puk;
158            mPin = pin;
159        }
160
161        abstract void onSimLockChangedResponse(boolean success);
162
163        @Override
164        public void run() {
165            try {
166                final boolean result = ITelephony.Stub.asInterface(ServiceManager
167                        .checkService("phone")).supplyPuk(mPuk, mPin);
168
169                post(new Runnable() {
170                    public void run() {
171                        onSimLockChangedResponse(result);
172                    }
173                });
174            } catch (RemoteException e) {
175                post(new Runnable() {
176                    public void run() {
177                        onSimLockChangedResponse(false);
178                    }
179                });
180            }
181        }
182    }
183
184    public void onClick(View v) {
185        if (v == mDelPukButton) {
186            if (mFocusedEntry != mPukText)
187                mPukText.requestFocus();
188            final Editable digits = mPukText.getEditableText();
189            final int len = digits.length();
190            if (len > 0) {
191                digits.delete(len-1, len);
192            }
193        } else if (v == mDelPinButton) {
194            if (mFocusedEntry != mPinText)
195                mPinText.requestFocus();
196            final Editable digits = mPinText.getEditableText();
197            final int len = digits.length();
198            if (len > 0) {
199                digits.delete(len-1, len);
200            }
201        }
202        mCallback.userActivity(DIGIT_PRESS_WAKE_MILLIS);
203    }
204
205    @Override
206    public void onFocusChange(View view, boolean hasFocus) {
207        if (hasFocus)
208            mFocusedEntry = (TextView) view;
209    }
210
211    private Dialog getSimUnlockProgressDialog() {
212        if (mSimUnlockProgressDialog == null) {
213            mSimUnlockProgressDialog = new ProgressDialog(mContext);
214            mSimUnlockProgressDialog.setMessage(mContext.getString(
215                    R.string.kg_sim_unlock_progress_dialog_message));
216            mSimUnlockProgressDialog.setIndeterminate(true);
217            mSimUnlockProgressDialog.setCancelable(false);
218            if (!(mContext instanceof Activity)) {
219                mSimUnlockProgressDialog.getWindow().setType(
220                        WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
221            }
222        }
223        return mSimUnlockProgressDialog;
224    }
225
226    private void checkPuk() {
227        // make sure the puk is at least 8 digits long.
228        if (mPukText.getText().length() < 8) {
229            // otherwise, display a message to the user, and don't submit.
230            mNavigationManager.setMessage(R.string.kg_invalid_sim_puk_hint);
231            mPukText.setText("");
232            return;
233        }
234
235        // make sure the PIN is between 4 and 8 digits
236        if (mPinText.getText().length() < 4
237                || mPinText.getText().length() > 8) {
238            // otherwise, display a message to the user, and don't submit.
239            mNavigationManager.setMessage(R.string.kg_invalid_sim_pin_hint);
240            mPinText.setText("");
241            return;
242        }
243
244        getSimUnlockProgressDialog().show();
245
246        if (!mCheckInProgress) {
247            mCheckInProgress = true;
248            new CheckSimPuk(mPukText.getText().toString(),
249                    mPinText.getText().toString()) {
250                void onSimLockChangedResponse(final boolean success) {
251                    mPinText.post(new Runnable() {
252                        public void run() {
253                            if (mSimUnlockProgressDialog != null) {
254                                mSimUnlockProgressDialog.hide();
255                            }
256                            if (success) {
257                                mCallback.dismiss(true);
258                            } else {
259                                mNavigationManager.setMessage(R.string.kg_invalid_puk);
260                                mPukText.setText("");
261                                mPinText.setText("");
262                            }
263                            mCheckInProgress = false;
264                        }
265                    });
266                }
267            }.start();
268        }
269    }
270
271    @Override
272    public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
273        // Check if this was the result of hitting the enter key
274        mCallback.userActivity(DIGIT_PRESS_WAKE_MILLIS);
275        if (event.getAction() == MotionEvent.ACTION_DOWN) {
276            if (actionId == EditorInfo.IME_NULL
277                || actionId == EditorInfo.IME_ACTION_DONE
278                || actionId == EditorInfo.IME_ACTION_NEXT) {
279                if (view == mPukText && mPukText.getText().length() < 8) {
280                    mNavigationManager.setMessage(R.string.kg_invalid_sim_puk_hint);
281                    mPukText.setText("");
282                    mPukText.requestFocus();
283                    return true;
284                } else if (view == mPinText) {
285                    if (mPinText.getText().length() < 4 || mPinText.getText().length() > 8) {
286                        mNavigationManager.setMessage(R.string.kg_invalid_sim_pin_hint);
287                        mPinText.setText("");
288                        mPinText.requestFocus();
289                    } else {
290                        checkPuk();
291                    }
292                    return true;
293                }
294            }
295        }
296        return false;
297    }
298
299    @Override
300    public void setLockPatternUtils(LockPatternUtils utils) {
301        mLockPatternUtils = utils;
302    }
303
304    @Override
305    public void reset() {
306        mNavigationManager.setMessage(R.string.kg_sim_puk_recovery_hint);
307        mPinText.setText("");
308        mPukText.setText("");
309        mPukText.requestFocus();
310    }
311
312    @Override
313    public KeyguardSecurityCallback getCallback() {
314        return mCallback;
315    }
316
317}
318