1 /*
2  * Copyright (C) 2008 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 
17 package com.android.phone;
18 
19 import android.content.Context;
20 import android.os.AsyncResult;
21 import android.os.Bundle;
22 import android.os.Handler;
23 import android.os.Message;
24 import android.os.PersistableBundle;
25 import android.telephony.CarrierConfigManager;
26 import android.text.Editable;
27 import android.text.Spannable;
28 import android.text.TextUtils;
29 import android.text.TextWatcher;
30 import android.text.method.DialerKeyListener;
31 import android.util.Log;
32 import android.view.KeyEvent;
33 import android.view.View;
34 import android.widget.Button;
35 import android.widget.EditText;
36 import android.widget.LinearLayout;
37 import android.widget.TextView;
38 
39 import com.android.internal.telephony.Phone;
40 
41 /**
42  * "SIM network unlock" PIN entry screen.
43  *
44  * @see PhoneGlobals.EVENT_SIM_NETWORK_LOCKED
45  *
46  * TODO: This UI should be part of the lock screen, not the
47  * phone app (see bug 1804111).
48  */
49 public class IccNetworkDepersonalizationPanel extends IccPanel {
50 
51     /**
52      * Tracks whether there is an instance of the network depersonalization dialog showing or not.
53      * Ensures only a single instance of the dialog is visible.
54      */
55     private static boolean sShowingDialog = false;
56 
57     //debug constants
58     private static final boolean DBG = false;
59 
60     //events
61     private static final int EVENT_ICC_NTWRK_DEPERSONALIZATION_RESULT = 100;
62 
63     private Phone mPhone;
64 
65     //UI elements
66     private EditText     mPinEntry;
67     private LinearLayout mEntryPanel;
68     private LinearLayout mStatusPanel;
69     private TextView     mStatusText;
70 
71     private Button       mUnlockButton;
72     private Button       mDismissButton;
73 
74     /**
75      * Shows the network depersonalization dialog, but only if it is not already visible.
76      */
showDialog()77     public static void showDialog() {
78         if (sShowingDialog) {
79             Log.i(TAG, "[IccNetworkDepersonalizationPanel] - showDialog; skipped already shown.");
80             return;
81         }
82         Log.i(TAG, "[IccNetworkDepersonalizationPanel] - showDialog; showing dialog.");
83         sShowingDialog = true;
84         IccNetworkDepersonalizationPanel ndpPanel =
85                 new IccNetworkDepersonalizationPanel(PhoneGlobals.getInstance());
86         ndpPanel.show();
87     }
88 
89     //private textwatcher to control text entry.
90     private TextWatcher mPinEntryWatcher = new TextWatcher() {
91         public void beforeTextChanged(CharSequence buffer, int start, int olen, int nlen) {
92         }
93 
94         public void onTextChanged(CharSequence buffer, int start, int olen, int nlen) {
95         }
96 
97         public void afterTextChanged(Editable buffer) {
98             if (SpecialCharSequenceMgr.handleChars(
99                     getContext(), buffer.toString())) {
100                 mPinEntry.getText().clear();
101             }
102         }
103     };
104 
105     //handler for unlock function results
106     private Handler mHandler = new Handler() {
107         public void handleMessage(Message msg) {
108             if (msg.what == EVENT_ICC_NTWRK_DEPERSONALIZATION_RESULT) {
109                 AsyncResult res = (AsyncResult) msg.obj;
110                 if (res.exception != null) {
111                     if (DBG) log("network depersonalization request failure.");
112                     indicateError();
113                     postDelayed(new Runnable() {
114                                     public void run() {
115                                         hideAlert();
116                                         mPinEntry.getText().clear();
117                                         mPinEntry.requestFocus();
118                                     }
119                                 }, 3000);
120                 } else {
121                     if (DBG) log("network depersonalization success.");
122                     indicateSuccess();
123                     postDelayed(new Runnable() {
124                                     public void run() {
125                                         dismiss();
126                                     }
127                                 }, 3000);
128                 }
129             }
130         }
131     };
132 
133     //constructor
IccNetworkDepersonalizationPanel(Context context)134     public IccNetworkDepersonalizationPanel(Context context) {
135         super(context);
136     }
137 
138     @Override
onCreate(Bundle icicle)139     protected void onCreate(Bundle icicle) {
140         super.onCreate(icicle);
141         setContentView(R.layout.sim_ndp);
142 
143         // PIN entry text field
144         mPinEntry = (EditText) findViewById(R.id.pin_entry);
145         mPinEntry.setKeyListener(DialerKeyListener.getInstance());
146         mPinEntry.setOnClickListener(mUnlockListener);
147 
148         // Attach the textwatcher
149         CharSequence text = mPinEntry.getText();
150         Spannable span = (Spannable) text;
151         span.setSpan(mPinEntryWatcher, 0, text.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
152 
153         mEntryPanel = (LinearLayout) findViewById(R.id.entry_panel);
154 
155         mUnlockButton = (Button) findViewById(R.id.ndp_unlock);
156         mUnlockButton.setOnClickListener(mUnlockListener);
157 
158         // The "Dismiss" button is present in some (but not all) products,
159         // based on the "KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL" variable.
160         mDismissButton = (Button) findViewById(R.id.ndp_dismiss);
161         PersistableBundle carrierConfig = PhoneGlobals.getInstance().getCarrierConfig();
162         if (carrierConfig.getBoolean(
163                 CarrierConfigManager.KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL)) {
164             if (DBG) log("Enabling 'Dismiss' button...");
165             mDismissButton.setVisibility(View.VISIBLE);
166             mDismissButton.setOnClickListener(mDismissListener);
167         } else {
168             if (DBG) log("Removing 'Dismiss' button...");
169             mDismissButton.setVisibility(View.GONE);
170         }
171 
172         //status panel is used since we're having problems with the alert dialog.
173         mStatusPanel = (LinearLayout) findViewById(R.id.status_panel);
174         mStatusText = (TextView) findViewById(R.id.status_text);
175 
176         mPhone = PhoneGlobals.getPhone();
177     }
178 
179     @Override
onStart()180     protected void onStart() {
181         super.onStart();
182     }
183 
184     @Override
onStop()185     public void onStop() {
186         super.onStop();
187         Log.i(TAG, "[IccNetworkDepersonalizationPanel] - showDialog; hiding dialog.");
188         sShowingDialog = false;
189     }
190 
191     //Mirrors IccPinUnlockPanel.onKeyDown().
onKeyDown(int keyCode, KeyEvent event)192     public boolean onKeyDown(int keyCode, KeyEvent event) {
193         if (keyCode == KeyEvent.KEYCODE_BACK) {
194             return true;
195         }
196 
197         return super.onKeyDown(keyCode, event);
198     }
199 
200     View.OnClickListener mUnlockListener = new View.OnClickListener() {
201         public void onClick(View v) {
202             String pin = mPinEntry.getText().toString();
203 
204             if (TextUtils.isEmpty(pin)) {
205                 return;
206             }
207 
208             if (DBG) log("requesting network depersonalization with code " + pin);
209             mPhone.getIccCard().supplyNetworkDepersonalization(pin,
210                     Message.obtain(mHandler, EVENT_ICC_NTWRK_DEPERSONALIZATION_RESULT));
211             indicateBusy();
212         }
213     };
214 
indicateBusy()215     private void indicateBusy() {
216         mStatusText.setText(R.string.requesting_unlock);
217         mEntryPanel.setVisibility(View.GONE);
218         mStatusPanel.setVisibility(View.VISIBLE);
219     }
220 
indicateError()221     private void indicateError() {
222         mStatusText.setText(R.string.unlock_failed);
223         mEntryPanel.setVisibility(View.GONE);
224         mStatusPanel.setVisibility(View.VISIBLE);
225     }
226 
indicateSuccess()227     private void indicateSuccess() {
228         mStatusText.setText(R.string.unlock_success);
229         mEntryPanel.setVisibility(View.GONE);
230         mStatusPanel.setVisibility(View.VISIBLE);
231     }
232 
hideAlert()233     private void hideAlert() {
234         mEntryPanel.setVisibility(View.VISIBLE);
235         mStatusPanel.setVisibility(View.GONE);
236     }
237 
238     View.OnClickListener mDismissListener = new View.OnClickListener() {
239             public void onClick(View v) {
240                 if (DBG) log("mDismissListener: skipping depersonalization...");
241                 dismiss();
242             }
243         };
244 
log(String msg)245     private void log(String msg) {
246         Log.v(TAG, "[IccNetworkDepersonalizationPanel] " + msg);
247     }
248 }
249