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