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.telephony.TelephonyManager; 27 import android.text.Editable; 28 import android.text.Spannable; 29 import android.text.TextUtils; 30 import android.text.TextWatcher; 31 import android.text.method.DialerKeyListener; 32 import android.util.Log; 33 import android.view.KeyEvent; 34 import android.view.View; 35 import android.widget.Button; 36 import android.widget.EditText; 37 import android.widget.LinearLayout; 38 import android.widget.TextView; 39 40 import com.android.internal.telephony.Phone; 41 import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState; 42 43 /** 44 * "SIM network unlock" PIN entry screen. 45 * 46 * @see PhoneGlobals.EVENT_SIM_NETWORK_LOCKED 47 * 48 * TODO: This UI should be part of the lock screen, not the 49 * phone app (see bug 1804111). 50 */ 51 public class IccNetworkDepersonalizationPanel extends IccPanel { 52 53 /** 54 * Tracks whether there is an instance of the network depersonalization dialog showing or not. 55 * Ensures only a single instance of the dialog is visible. 56 */ 57 private static boolean [] sShowingDialog = 58 new boolean[TelephonyManager.getDefault().getSupportedModemCount()]; 59 60 //debug constants 61 private static final boolean DBG = false; 62 63 //events 64 private static final int EVENT_ICC_NTWRK_DEPERSONALIZATION_RESULT = 100; 65 66 private Phone mPhone; 67 private int mPersoSubtype; 68 private static IccNetworkDepersonalizationPanel [] sNdpPanel = 69 new IccNetworkDepersonalizationPanel[ 70 TelephonyManager.getDefault().getSupportedModemCount()]; 71 72 //UI elements 73 private EditText mPinEntry; 74 private LinearLayout mEntryPanel; 75 private LinearLayout mStatusPanel; 76 private TextView mPersoSubtypeText; 77 private PersoSubState mPersoSubState; 78 private TextView mStatusText; 79 80 private Button mUnlockButton; 81 private Button mDismissButton; 82 83 enum statusType { 84 ENTRY, 85 IN_PROGRESS, 86 ERROR, 87 SUCCESS 88 } 89 90 /** 91 * Shows the network depersonalization dialog, but only if it is not already visible. 92 */ showDialog(Phone phone, int subType)93 public static void showDialog(Phone phone, int subType) { 94 int phoneId = phone == null ? 0: phone.getPhoneId(); 95 if (phoneId >= sShowingDialog.length) { 96 Log.e(TAG, "[IccNetworkDepersonalizationPanel] showDialog; invalid phoneId" + phoneId); 97 return; 98 } 99 if (sShowingDialog[phoneId]) { 100 Log.i(TAG, "[IccNetworkDepersonalizationPanel] - showDialog; skipped already shown."); 101 return; 102 } 103 Log.i(TAG, "[IccNetworkDepersonalizationPanel] - showDialog; showing dialog."); 104 sShowingDialog[phoneId] = true; 105 sNdpPanel[phoneId] = new IccNetworkDepersonalizationPanel(PhoneGlobals.getInstance(), 106 phone, subType); 107 sNdpPanel[phoneId].show(); 108 } 109 dialogDismiss(int phoneId)110 public static void dialogDismiss(int phoneId) { 111 if (phoneId >= sShowingDialog.length) { 112 Log.e(TAG, "[IccNetworkDepersonalizationPanel] - dismiss; invalid phoneId " + phoneId); 113 return; 114 } 115 if (sNdpPanel[phoneId] != null && sShowingDialog[phoneId]) { 116 sNdpPanel[phoneId].dismiss(); 117 } 118 } 119 120 //private textwatcher to control text entry. 121 private TextWatcher mPinEntryWatcher = new TextWatcher() { 122 public void beforeTextChanged(CharSequence buffer, int start, int olen, int nlen) { 123 } 124 125 public void onTextChanged(CharSequence buffer, int start, int olen, int nlen) { 126 } 127 128 public void afterTextChanged(Editable buffer) { 129 if (SpecialCharSequenceMgr.handleChars( 130 getContext(), buffer.toString())) { 131 mPinEntry.getText().clear(); 132 } 133 } 134 }; 135 136 //handler for unlock function results 137 private Handler mHandler = new Handler() { 138 public void handleMessage(Message msg) { 139 if (msg.what == EVENT_ICC_NTWRK_DEPERSONALIZATION_RESULT) { 140 AsyncResult res = (AsyncResult) msg.obj; 141 if (res.exception != null) { 142 if (DBG) log("network depersonalization request failure."); 143 displayStatus(statusType.ERROR.name()); 144 postDelayed(new Runnable() { 145 public void run() { 146 hideAlert(); 147 mPinEntry.getText().clear(); 148 mPinEntry.requestFocus(); 149 } 150 }, 3000); 151 } else { 152 if (DBG) log("network depersonalization success."); 153 displayStatus(statusType.SUCCESS.name()); 154 postDelayed(new Runnable() { 155 public void run() { 156 dismiss(); 157 } 158 }, 3000); 159 } 160 } 161 } 162 }; 163 164 165 //constructor IccNetworkDepersonalizationPanel(Context context)166 public IccNetworkDepersonalizationPanel(Context context) { 167 super(context); 168 mPhone = PhoneGlobals.getPhone(); 169 mPersoSubtype = PersoSubState.PERSOSUBSTATE_SIM_NETWORK.ordinal(); 170 } 171 172 //constructor IccNetworkDepersonalizationPanel(Context context, Phone phone, int subtype)173 public IccNetworkDepersonalizationPanel(Context context, Phone phone, 174 int subtype) { 175 super(context); 176 mPhone = phone == null ? PhoneGlobals.getPhone() : phone; 177 mPersoSubtype = subtype; 178 } 179 180 @Override onCreate(Bundle icicle)181 protected void onCreate(Bundle icicle) { 182 super.onCreate(icicle); 183 setContentView(R.layout.sim_ndp); 184 185 // PIN entry text field 186 mPinEntry = (EditText) findViewById(R.id.pin_entry); 187 mPinEntry.setKeyListener(DialerKeyListener.getInstance()); 188 mPinEntry.setOnClickListener(mUnlockListener); 189 190 // Attach the textwatcher 191 CharSequence text = mPinEntry.getText(); 192 Spannable span = (Spannable) text; 193 span.setSpan(mPinEntryWatcher, 0, text.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); 194 195 mEntryPanel = (LinearLayout) findViewById(R.id.entry_panel); 196 mPersoSubtypeText = (TextView) findViewById(R.id.perso_subtype_text); 197 displayStatus(statusType.ENTRY.name()); 198 199 mUnlockButton = (Button) findViewById(R.id.ndp_unlock); 200 mUnlockButton.setOnClickListener(mUnlockListener); 201 202 // The "Dismiss" button is present in some (but not all) products, 203 // based on the "KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL" variable. 204 mDismissButton = (Button) findViewById(R.id.ndp_dismiss); 205 PersistableBundle carrierConfig = PhoneGlobals.getInstance().getCarrierConfig(); 206 if (carrierConfig.getBoolean( 207 CarrierConfigManager.KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL)) { 208 if (DBG) log("Enabling 'Dismiss' button..."); 209 mDismissButton.setVisibility(View.VISIBLE); 210 mDismissButton.setOnClickListener(mDismissListener); 211 } else { 212 if (DBG) log("Removing 'Dismiss' button..."); 213 mDismissButton.setVisibility(View.GONE); 214 } 215 216 //status panel is used since we're having problems with the alert dialog. 217 mStatusPanel = (LinearLayout) findViewById(R.id.status_panel); 218 mStatusText = (TextView) findViewById(R.id.status_text); 219 } 220 221 @Override onStart()222 protected void onStart() { 223 super.onStart(); 224 } 225 226 @Override onStop()227 public void onStop() { 228 super.onStop(); 229 Log.i(TAG, "[IccNetworkDepersonalizationPanel] - showDialog; hiding dialog."); 230 int phoneId = mPhone == null ? 0 : mPhone.getPhoneId(); 231 if (phoneId >= sShowingDialog.length) { 232 Log.e(TAG, "[IccNetworkDepersonalizationPanel] - onStop; invalid phoneId " + phoneId); 233 return; 234 } 235 sShowingDialog[phoneId] = false; 236 } 237 238 //Mirrors IccPinUnlockPanel.onKeyDown(). onKeyDown(int keyCode, KeyEvent event)239 public boolean onKeyDown(int keyCode, KeyEvent event) { 240 if (keyCode == KeyEvent.KEYCODE_BACK) { 241 return true; 242 } 243 244 return super.onKeyDown(keyCode, event); 245 } 246 247 View.OnClickListener mUnlockListener = new View.OnClickListener() { 248 public void onClick(View v) { 249 String pin = mPinEntry.getText().toString(); 250 251 if (TextUtils.isEmpty(pin)) { 252 return; 253 } 254 255 log("Requesting De-Personalization for subtype " + mPersoSubtype); 256 257 try { 258 mPhone.getIccCard().supplySimDepersonalization(mPersoSubState,pin, 259 Message.obtain(mHandler, EVENT_ICC_NTWRK_DEPERSONALIZATION_RESULT)); 260 } catch (NullPointerException ex) { 261 log("NullPointerException @supplySimDepersonalization" + ex); 262 } 263 displayStatus(statusType.IN_PROGRESS.name()); 264 } 265 }; 266 displayStatus(String type)267 private void displayStatus(String type) { 268 int label = 0; 269 270 mPersoSubState = PersoSubState.values()[mPersoSubtype]; 271 log("displayStatus mPersoSubState: " +mPersoSubState.name() +"type: " +type); 272 273 label = getContext().getResources().getIdentifier(mPersoSubState.name() 274 + "_" + type, "string", "android"); 275 276 if (label == 0) { 277 log ("Unable to get the PersoSubType string"); 278 return; 279 } 280 281 if(!PersoSubState.isPersoLocked(mPersoSubState)) { 282 log ("Unsupported Perso Subtype :" + mPersoSubState.name()); 283 return; 284 } 285 286 if (type == statusType.ENTRY.name()) { 287 String displayText = getContext().getString(label); 288 mPersoSubtypeText.setText(displayText); 289 } else { 290 mStatusText.setText(label); 291 mEntryPanel.setVisibility(View.GONE); 292 mStatusPanel.setVisibility(View.VISIBLE); 293 } 294 } 295 hideAlert()296 private void hideAlert() { 297 mEntryPanel.setVisibility(View.VISIBLE); 298 mStatusPanel.setVisibility(View.GONE); 299 } 300 301 View.OnClickListener mDismissListener = new View.OnClickListener() { 302 public void onClick(View v) { 303 if (DBG) log("mDismissListener: skipping depersonalization..."); 304 dismiss(); 305 } 306 }; 307 log(String msg)308 private void log(String msg) { 309 Log.d(TAG, "[IccNetworkDepersonalizationPanel] " + msg); 310 } 311 } 312