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