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