KeyguardSimPinView.java revision 7d5e00ab2b5134d11e40b5a84fa363f8e8b24d68
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 */
16
17package com.android.keyguard;
18
19import com.android.internal.telephony.ITelephony;
20
21import android.content.Context;
22import android.app.Activity;
23import android.app.Dialog;
24import android.app.ProgressDialog;
25import android.os.RemoteException;
26import android.os.ServiceManager;
27import android.text.Editable;
28import android.text.InputType;
29import android.text.TextWatcher;
30import android.text.method.DigitsKeyListener;
31import android.util.AttributeSet;
32import android.view.View;
33import android.view.WindowManager;
34import android.widget.TextView.OnEditorActionListener;
35
36/**
37 * Displays a PIN pad for unlocking.
38 */
39public class KeyguardSimPinView extends KeyguardAbsKeyInputView
40        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
41
42    private ProgressDialog mSimUnlockProgressDialog = null;
43    private volatile boolean mSimCheckInProgress;
44
45    public KeyguardSimPinView(Context context) {
46        this(context, null);
47    }
48
49    public KeyguardSimPinView(Context context, AttributeSet attrs) {
50        super(context, attrs);
51    }
52
53    public void resetState() {
54        mSecurityMessageDisplay.setMessage(R.string.kg_sim_pin_instructions, true);
55        mPasswordEntry.setEnabled(true);
56    }
57
58    @Override
59    protected boolean shouldLockout(long deadline) {
60        // SIM PIN doesn't have a timed lockout
61        return false;
62    }
63
64    @Override
65    protected int getPasswordTextViewId() {
66        return R.id.pinEntry;
67    }
68
69    @Override
70    protected void onFinishInflate() {
71        super.onFinishInflate();
72
73        final View ok = findViewById(R.id.key_enter);
74        if (ok != null) {
75            ok.setOnClickListener(new View.OnClickListener() {
76                @Override
77                public void onClick(View v) {
78                    doHapticKeyClick();
79                    verifyPasswordAndUnlock();
80                }
81            });
82        }
83
84        // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
85        // not a separate view
86        View pinDelete = findViewById(R.id.delete_button);
87        if (pinDelete != null) {
88            pinDelete.setVisibility(View.VISIBLE);
89            pinDelete.setOnClickListener(new OnClickListener() {
90                public void onClick(View v) {
91                    CharSequence str = mPasswordEntry.getText();
92                    if (str.length() > 0) {
93                        mPasswordEntry.setText(str.subSequence(0, str.length()-1));
94                    }
95                    doHapticKeyClick();
96                }
97            });
98            pinDelete.setOnLongClickListener(new View.OnLongClickListener() {
99                public boolean onLongClick(View v) {
100                    mPasswordEntry.setText("");
101                    doHapticKeyClick();
102                    return true;
103                }
104            });
105        }
106
107        mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
108        mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
109                | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
110
111        mPasswordEntry.requestFocus();
112    }
113
114    @Override
115    public void showUsabilityHint() {
116    }
117
118    @Override
119    public void onPause() {
120        // dismiss the dialog.
121        if (mSimUnlockProgressDialog != null) {
122            mSimUnlockProgressDialog.dismiss();
123            mSimUnlockProgressDialog = null;
124        }
125    }
126
127    /**
128     * Since the IPC can block, we want to run the request in a separate thread
129     * with a callback.
130     */
131    private abstract class CheckSimPin extends Thread {
132        private final String mPin;
133
134        protected CheckSimPin(String pin) {
135            mPin = pin;
136        }
137
138        abstract void onSimCheckResponse(boolean success);
139
140        @Override
141        public void run() {
142            try {
143                final boolean result = ITelephony.Stub.asInterface(ServiceManager
144                        .checkService("phone")).supplyPin(mPin);
145                post(new Runnable() {
146                    public void run() {
147                        onSimCheckResponse(result);
148                    }
149                });
150            } catch (RemoteException e) {
151                post(new Runnable() {
152                    public void run() {
153                        onSimCheckResponse(false);
154                    }
155                });
156            }
157        }
158    }
159
160    private Dialog getSimUnlockProgressDialog() {
161        if (mSimUnlockProgressDialog == null) {
162            mSimUnlockProgressDialog = new ProgressDialog(mContext);
163            mSimUnlockProgressDialog.setMessage(
164                    mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
165            mSimUnlockProgressDialog.setIndeterminate(true);
166            mSimUnlockProgressDialog.setCancelable(false);
167            if (!(mContext instanceof Activity)) {
168                mSimUnlockProgressDialog.getWindow().setType(
169                        WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
170            }
171        }
172        return mSimUnlockProgressDialog;
173    }
174
175    @Override
176    protected void verifyPasswordAndUnlock() {
177        String entry = mPasswordEntry.getText().toString();
178
179        if (entry.length() < 4) {
180            // otherwise, display a message to the user, and don't submit.
181            mSecurityMessageDisplay.setMessage(R.string.kg_invalid_sim_pin_hint, true);
182            mPasswordEntry.setText("");
183            mCallback.userActivity(0);
184            return;
185        }
186
187        getSimUnlockProgressDialog().show();
188
189        if (!mSimCheckInProgress) {
190            mSimCheckInProgress = true; // there should be only one
191            new CheckSimPin(mPasswordEntry.getText().toString()) {
192                void onSimCheckResponse(final boolean success) {
193                    post(new Runnable() {
194                        public void run() {
195                            if (mSimUnlockProgressDialog != null) {
196                                mSimUnlockProgressDialog.hide();
197                            }
198                            if (success) {
199                                // before closing the keyguard, report back that the sim is unlocked
200                                // so it knows right away.
201                                KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked();
202                                mCallback.dismiss(true);
203                            } else {
204                                mSecurityMessageDisplay.setMessage
205                                    (R.string.kg_password_wrong_pin_code, true);
206                                mPasswordEntry.setText("");
207                            }
208                            mCallback.userActivity(0);
209                            mSimCheckInProgress = false;
210                        }
211                    });
212                }
213            }.start();
214        }
215    }
216}
217
218