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