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