ApnEditor.java revision 67c70267d16996ced73ac2e7648b0a79baed3c16
1/* 2 * Copyright (C) 2006 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.settings; 18 19import android.app.AlertDialog; 20import android.app.Dialog; 21import android.content.ContentUris; 22import android.content.ContentValues; 23import android.content.Intent; 24import android.content.SharedPreferences; 25import android.content.res.Resources; 26import android.database.Cursor; 27import android.net.Uri; 28import android.os.Bundle; 29import android.os.SystemProperties; 30import android.preference.EditTextPreference; 31import android.preference.ListPreference; 32import android.preference.Preference; 33import android.preference.PreferenceActivity; 34import android.provider.Telephony; 35import android.util.Log; 36import android.view.KeyEvent; 37import android.view.Menu; 38import android.view.MenuItem; 39 40import com.android.internal.telephony.TelephonyProperties; 41import com.android.internal.telephony.RILConstants; 42 43 44public class ApnEditor extends PreferenceActivity 45 implements SharedPreferences.OnSharedPreferenceChangeListener, 46 Preference.OnPreferenceChangeListener { 47 48 private final static String TAG = ApnEditor.class.getSimpleName(); 49 50 private final static String SAVED_POS = "pos"; 51 private final static String KEY_AUTH_TYPE = "auth_type"; 52 private final static String KEY_PROTOCOL = "apn_protocol"; 53 54 private static final int MENU_DELETE = Menu.FIRST; 55 private static final int MENU_SAVE = Menu.FIRST + 1; 56 private static final int MENU_CANCEL = Menu.FIRST + 2; 57 private static final int ERROR_DIALOG_ID = 0; 58 59 private static String sNotSet; 60 private EditTextPreference mName; 61 private EditTextPreference mApn; 62 private EditTextPreference mProxy; 63 private EditTextPreference mPort; 64 private EditTextPreference mUser; 65 private EditTextPreference mServer; 66 private EditTextPreference mPassword; 67 private EditTextPreference mMmsc; 68 private EditTextPreference mMcc; 69 private EditTextPreference mMnc; 70 private EditTextPreference mMmsProxy; 71 private EditTextPreference mMmsPort; 72 private ListPreference mAuthType; 73 private EditTextPreference mApnType; 74 private ListPreference mProtocol; 75 76 private String mCurMnc; 77 private String mCurMcc; 78 79 private Uri mUri; 80 private Cursor mCursor; 81 private boolean mNewApn; 82 private boolean mFirstTime; 83 private Resources mRes; 84 85 /** 86 * Standard projection for the interesting columns of a normal note. 87 */ 88 private static final String[] sProjection = new String[] { 89 Telephony.Carriers._ID, // 0 90 Telephony.Carriers.NAME, // 1 91 Telephony.Carriers.APN, // 2 92 Telephony.Carriers.PROXY, // 3 93 Telephony.Carriers.PORT, // 4 94 Telephony.Carriers.USER, // 5 95 Telephony.Carriers.SERVER, // 6 96 Telephony.Carriers.PASSWORD, // 7 97 Telephony.Carriers.MMSC, // 8 98 Telephony.Carriers.MCC, // 9 99 Telephony.Carriers.MNC, // 10 100 Telephony.Carriers.NUMERIC, // 11 101 Telephony.Carriers.MMSPROXY,// 12 102 Telephony.Carriers.MMSPORT, // 13 103 Telephony.Carriers.AUTH_TYPE, // 14 104 Telephony.Carriers.TYPE, // 15 105 Telephony.Carriers.PROTOCOL, // 16 106 }; 107 108 private static final int ID_INDEX = 0; 109 private static final int NAME_INDEX = 1; 110 private static final int APN_INDEX = 2; 111 private static final int PROXY_INDEX = 3; 112 private static final int PORT_INDEX = 4; 113 private static final int USER_INDEX = 5; 114 private static final int SERVER_INDEX = 6; 115 private static final int PASSWORD_INDEX = 7; 116 private static final int MMSC_INDEX = 8; 117 private static final int MCC_INDEX = 9; 118 private static final int MNC_INDEX = 10; 119 private static final int MMSPROXY_INDEX = 12; 120 private static final int MMSPORT_INDEX = 13; 121 private static final int AUTH_TYPE_INDEX = 14; 122 private static final int TYPE_INDEX = 15; 123 private static final int PROTOCOL_INDEX = 16; 124 125 126 @Override 127 protected void onCreate(Bundle icicle) { 128 super.onCreate(icicle); 129 130 addPreferencesFromResource(R.xml.apn_editor); 131 132 sNotSet = getResources().getString(R.string.apn_not_set); 133 mName = (EditTextPreference) findPreference("apn_name"); 134 mApn = (EditTextPreference) findPreference("apn_apn"); 135 mProxy = (EditTextPreference) findPreference("apn_http_proxy"); 136 mPort = (EditTextPreference) findPreference("apn_http_port"); 137 mUser = (EditTextPreference) findPreference("apn_user"); 138 mServer = (EditTextPreference) findPreference("apn_server"); 139 mPassword = (EditTextPreference) findPreference("apn_password"); 140 mMmsProxy = (EditTextPreference) findPreference("apn_mms_proxy"); 141 mMmsPort = (EditTextPreference) findPreference("apn_mms_port"); 142 mMmsc = (EditTextPreference) findPreference("apn_mmsc"); 143 mMcc = (EditTextPreference) findPreference("apn_mcc"); 144 mMnc = (EditTextPreference) findPreference("apn_mnc"); 145 mApnType = (EditTextPreference) findPreference("apn_type"); 146 147 mAuthType = (ListPreference) findPreference(KEY_AUTH_TYPE); 148 mAuthType.setOnPreferenceChangeListener(this); 149 150 mProtocol = (ListPreference) findPreference(KEY_PROTOCOL); 151 mProtocol.setOnPreferenceChangeListener(this); 152 153 mRes = getResources(); 154 155 final Intent intent = getIntent(); 156 final String action = intent.getAction(); 157 158 mFirstTime = icicle == null; 159 160 if (action.equals(Intent.ACTION_EDIT)) { 161 mUri = intent.getData(); 162 } else if (action.equals(Intent.ACTION_INSERT)) { 163 if (mFirstTime || icicle.getInt(SAVED_POS) == 0) { 164 mUri = getContentResolver().insert(intent.getData(), new ContentValues()); 165 } else { 166 mUri = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, 167 icicle.getInt(SAVED_POS)); 168 } 169 mNewApn = true; 170 // If we were unable to create a new note, then just finish 171 // this activity. A RESULT_CANCELED will be sent back to the 172 // original activity if they requested a result. 173 if (mUri == null) { 174 Log.w(TAG, "Failed to insert new telephony provider into " 175 + getIntent().getData()); 176 finish(); 177 return; 178 } 179 180 // The new entry was created, so assume all will end well and 181 // set the result to be returned. 182 setResult(RESULT_OK, (new Intent()).setAction(mUri.toString())); 183 184 } else { 185 finish(); 186 return; 187 } 188 189 mCursor = managedQuery(mUri, sProjection, null, null); 190 mCursor.moveToFirst(); 191 192 fillUi(); 193 } 194 195 @Override 196 public void onResume() { 197 super.onResume(); 198 getPreferenceScreen().getSharedPreferences() 199 .registerOnSharedPreferenceChangeListener(this); 200 } 201 202 @Override 203 public void onPause() { 204 getPreferenceScreen().getSharedPreferences() 205 .unregisterOnSharedPreferenceChangeListener(this); 206 super.onPause(); 207 } 208 209 private void fillUi() { 210 if (mFirstTime) { 211 mFirstTime = false; 212 // Fill in all the values from the db in both text editor and summary 213 mName.setText(mCursor.getString(NAME_INDEX)); 214 mApn.setText(mCursor.getString(APN_INDEX)); 215 mProxy.setText(mCursor.getString(PROXY_INDEX)); 216 mPort.setText(mCursor.getString(PORT_INDEX)); 217 mUser.setText(mCursor.getString(USER_INDEX)); 218 mServer.setText(mCursor.getString(SERVER_INDEX)); 219 mPassword.setText(mCursor.getString(PASSWORD_INDEX)); 220 mMmsProxy.setText(mCursor.getString(MMSPROXY_INDEX)); 221 mMmsPort.setText(mCursor.getString(MMSPORT_INDEX)); 222 mMmsc.setText(mCursor.getString(MMSC_INDEX)); 223 mMcc.setText(mCursor.getString(MCC_INDEX)); 224 mMnc.setText(mCursor.getString(MNC_INDEX)); 225 mApnType.setText(mCursor.getString(TYPE_INDEX)); 226 if (mNewApn) { 227 String numeric = 228 SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC); 229 // MCC is first 3 chars and then in 2 - 3 chars of MNC 230 if (numeric != null && numeric.length() > 4) { 231 // Country code 232 String mcc = numeric.substring(0, 3); 233 // Network code 234 String mnc = numeric.substring(3); 235 // Auto populate MNC and MCC for new entries, based on what SIM reports 236 mMcc.setText(mcc); 237 mMnc.setText(mnc); 238 mCurMnc = mnc; 239 mCurMcc = mcc; 240 } 241 } 242 int authVal = mCursor.getInt(AUTH_TYPE_INDEX); 243 if (authVal != -1) { 244 mAuthType.setValueIndex(authVal); 245 } else { 246 mAuthType.setValue(null); 247 } 248 249 mProtocol.setValue(mCursor.getString(PROTOCOL_INDEX)); 250 } 251 252 mName.setSummary(checkNull(mName.getText())); 253 mApn.setSummary(checkNull(mApn.getText())); 254 mProxy.setSummary(checkNull(mProxy.getText())); 255 mPort.setSummary(checkNull(mPort.getText())); 256 mUser.setSummary(checkNull(mUser.getText())); 257 mServer.setSummary(checkNull(mServer.getText())); 258 mPassword.setSummary(starify(mPassword.getText())); 259 mMmsProxy.setSummary(checkNull(mMmsProxy.getText())); 260 mMmsPort.setSummary(checkNull(mMmsPort.getText())); 261 mMmsc.setSummary(checkNull(mMmsc.getText())); 262 mMcc.setSummary(checkNull(mMcc.getText())); 263 mMnc.setSummary(checkNull(mMnc.getText())); 264 mApnType.setSummary(checkNull(mApnType.getText())); 265 266 String authVal = mAuthType.getValue(); 267 if (authVal != null) { 268 int authValIndex = Integer.parseInt(authVal); 269 mAuthType.setValueIndex(authValIndex); 270 271 String []values = mRes.getStringArray(R.array.apn_auth_entries); 272 mAuthType.setSummary(values[authValIndex]); 273 } else { 274 mAuthType.setSummary(sNotSet); 275 } 276 277 mProtocol.setSummary( 278 checkNull(protocolDescription(mProtocol.getValue()))); 279 } 280 281 /** 282 * Returns the UI choice (e.g., "IPv4/IPv6") corresponding to the given 283 * raw value of the protocol preference (e.g., "IPV4V6"). If unknown, 284 * return null. 285 */ 286 private String protocolDescription(String raw) { 287 int protocolIndex = mProtocol.findIndexOfValue(raw); 288 if (protocolIndex == -1) { 289 return null; 290 } else { 291 String[] values = mRes.getStringArray(R.array.apn_protocol_entries); 292 try { 293 return values[protocolIndex]; 294 } catch (ArrayIndexOutOfBoundsException e) { 295 return null; 296 } 297 } 298 } 299 300 public boolean onPreferenceChange(Preference preference, Object newValue) { 301 String key = preference.getKey(); 302 if (KEY_AUTH_TYPE.equals(key)) { 303 try { 304 int index = Integer.parseInt((String) newValue); 305 mAuthType.setValueIndex(index); 306 307 String []values = mRes.getStringArray(R.array.apn_auth_entries); 308 mAuthType.setSummary(values[index]); 309 } catch (NumberFormatException e) { 310 return false; 311 } 312 return true; 313 } 314 315 if (KEY_PROTOCOL.equals(key)) { 316 String protocol = protocolDescription((String) newValue); 317 if (protocol == null) { 318 return false; 319 } 320 mProtocol.setSummary(protocol); 321 mProtocol.setValue((String) newValue); 322 } 323 return true; 324 } 325 326 @Override 327 public boolean onCreateOptionsMenu(Menu menu) { 328 super.onCreateOptionsMenu(menu); 329 // If it's a new APN, then cancel will delete the new entry in onPause 330 if (!mNewApn) { 331 menu.add(0, MENU_DELETE, 0, R.string.menu_delete) 332 .setIcon(R.drawable.ic_menu_delete_holo_dark); 333 } 334 menu.add(0, MENU_SAVE, 0, R.string.menu_save) 335 .setIcon(android.R.drawable.ic_menu_save); 336 menu.add(0, MENU_CANCEL, 0, R.string.menu_cancel) 337 .setIcon(android.R.drawable.ic_menu_close_clear_cancel); 338 return true; 339 } 340 341 @Override 342 public boolean onOptionsItemSelected(MenuItem item) { 343 switch (item.getItemId()) { 344 case MENU_DELETE: 345 deleteApn(); 346 return true; 347 case MENU_SAVE: 348 if (validateAndSave(false)) { 349 finish(); 350 } 351 return true; 352 case MENU_CANCEL: 353 if (mNewApn) { 354 getContentResolver().delete(mUri, null, null); 355 } 356 finish(); 357 return true; 358 } 359 return super.onOptionsItemSelected(item); 360 } 361 362 @Override 363 public boolean onKeyDown(int keyCode, KeyEvent event) { 364 switch (keyCode) { 365 case KeyEvent.KEYCODE_BACK: { 366 if (validateAndSave(false)) { 367 finish(); 368 } 369 return true; 370 } 371 } 372 return super.onKeyDown(keyCode, event); 373 } 374 375 @Override 376 protected void onSaveInstanceState(Bundle icicle) { 377 super.onSaveInstanceState(icicle); 378 if (validateAndSave(true)) { 379 icicle.putInt(SAVED_POS, mCursor.getInt(ID_INDEX)); 380 } 381 } 382 383 /** 384 * Check the key fields' validity and save if valid. 385 * @param force save even if the fields are not valid, if the app is 386 * being suspended 387 * @return true if the data was saved 388 */ 389 private boolean validateAndSave(boolean force) { 390 String name = checkNotSet(mName.getText()); 391 String apn = checkNotSet(mApn.getText()); 392 String mcc = checkNotSet(mMcc.getText()); 393 String mnc = checkNotSet(mMnc.getText()); 394 395 if (getErrorMsg() != null && !force) { 396 showDialog(ERROR_DIALOG_ID); 397 return false; 398 } 399 400 if (!mCursor.moveToFirst()) { 401 Log.w(TAG, 402 "Could not go to the first row in the Cursor when saving data."); 403 return false; 404 } 405 406 // If it's a new APN and a name or apn haven't been entered, then erase the entry 407 if (force && mNewApn && name.length() < 1 && apn.length() < 1) { 408 getContentResolver().delete(mUri, null, null); 409 return false; 410 } 411 412 ContentValues values = new ContentValues(); 413 414 // Add a dummy name "Untitled", if the user exits the screen without adding a name but 415 // entered other information worth keeping. 416 values.put(Telephony.Carriers.NAME, 417 name.length() < 1 ? getResources().getString(R.string.untitled_apn) : name); 418 values.put(Telephony.Carriers.APN, apn); 419 values.put(Telephony.Carriers.PROXY, checkNotSet(mProxy.getText())); 420 values.put(Telephony.Carriers.PORT, checkNotSet(mPort.getText())); 421 values.put(Telephony.Carriers.MMSPROXY, checkNotSet(mMmsProxy.getText())); 422 values.put(Telephony.Carriers.MMSPORT, checkNotSet(mMmsPort.getText())); 423 values.put(Telephony.Carriers.USER, checkNotSet(mUser.getText())); 424 values.put(Telephony.Carriers.SERVER, checkNotSet(mServer.getText())); 425 values.put(Telephony.Carriers.PASSWORD, checkNotSet(mPassword.getText())); 426 values.put(Telephony.Carriers.MMSC, checkNotSet(mMmsc.getText())); 427 428 String authVal = mAuthType.getValue(); 429 if (authVal != null) { 430 values.put(Telephony.Carriers.AUTH_TYPE, Integer.parseInt(authVal)); 431 } 432 433 values.put(Telephony.Carriers.PROTOCOL, checkNotSet(mProtocol.getValue())); 434 435 // Hardcode IPv4 roaming for now until the carriers sort out all the 436 // billing arrangements. 437 values.put(Telephony.Carriers.ROAMING_PROTOCOL, 438 RILConstants.SETUP_DATA_PROTOCOL_IP); 439 440 values.put(Telephony.Carriers.TYPE, checkNotSet(mApnType.getText())); 441 442 values.put(Telephony.Carriers.MCC, mcc); 443 values.put(Telephony.Carriers.MNC, mnc); 444 445 values.put(Telephony.Carriers.NUMERIC, mcc + mnc); 446 447 if (mCurMnc != null && mCurMcc != null) { 448 if (mCurMnc.equals(mnc) && mCurMcc.equals(mcc)) { 449 values.put(Telephony.Carriers.CURRENT, 1); 450 } 451 } 452 453 getContentResolver().update(mUri, values, null, null); 454 455 return true; 456 } 457 458 private String getErrorMsg() { 459 String errorMsg = null; 460 461 String name = checkNotSet(mName.getText()); 462 String apn = checkNotSet(mApn.getText()); 463 String mcc = checkNotSet(mMcc.getText()); 464 String mnc = checkNotSet(mMnc.getText()); 465 466 if (name.length() < 1) { 467 errorMsg = mRes.getString(R.string.error_name_empty); 468 } else if (apn.length() < 1) { 469 errorMsg = mRes.getString(R.string.error_apn_empty); 470 } else if (mcc.length() != 3) { 471 errorMsg = mRes.getString(R.string.error_mcc_not3); 472 } else if ((mnc.length() & 0xFFFE) != 2) { 473 errorMsg = mRes.getString(R.string.error_mnc_not23); 474 } 475 476 return errorMsg; 477 } 478 479 @Override 480 protected Dialog onCreateDialog(int id) { 481 482 if (id == ERROR_DIALOG_ID) { 483 String msg = getErrorMsg(); 484 485 return new AlertDialog.Builder(this) 486 .setTitle(R.string.error_title) 487 .setPositiveButton(android.R.string.ok, null) 488 .setMessage(msg) 489 .create(); 490 } 491 492 return super.onCreateDialog(id); 493 } 494 495 @Override 496 protected void onPrepareDialog(int id, Dialog dialog) { 497 super.onPrepareDialog(id, dialog); 498 499 if (id == ERROR_DIALOG_ID) { 500 String msg = getErrorMsg(); 501 502 if (msg != null) { 503 ((AlertDialog)dialog).setMessage(msg); 504 } 505 } 506 } 507 508 private void deleteApn() { 509 getContentResolver().delete(mUri, null, null); 510 finish(); 511 } 512 513 private String starify(String value) { 514 if (value == null || value.length() == 0) { 515 return sNotSet; 516 } else { 517 char[] password = new char[value.length()]; 518 for (int i = 0; i < password.length; i++) { 519 password[i] = '*'; 520 } 521 return new String(password); 522 } 523 } 524 525 private String checkNull(String value) { 526 if (value == null || value.length() == 0) { 527 return sNotSet; 528 } else { 529 return value; 530 } 531 } 532 533 private String checkNotSet(String value) { 534 if (value == null || value.equals(sNotSet)) { 535 return ""; 536 } else { 537 return value; 538 } 539 } 540 541 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 542 Preference pref = findPreference(key); 543 if (pref != null) { 544 if (pref.equals(mPassword)){ 545 pref.setSummary(starify(sharedPreferences.getString(key, ""))); 546 } else { 547 pref.setSummary(checkNull(sharedPreferences.getString(key, ""))); 548 } 549 } 550 } 551} 552