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