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 17 package com.android.settings; 18 19 import static android.app.Activity.RESULT_OK; 20 import static android.content.Context.TELEPHONY_SERVICE; 21 22 import android.app.AlertDialog; 23 import android.app.Dialog; 24 import android.app.DialogFragment; 25 import android.content.ContentUris; 26 import android.content.ContentValues; 27 import android.content.Intent; 28 import android.content.res.Resources; 29 import android.database.Cursor; 30 import android.net.Uri; 31 import android.os.Bundle; 32 import android.provider.Telephony; 33 import android.support.v14.preference.MultiSelectListPreference; 34 import android.support.v14.preference.SwitchPreference; 35 import android.support.v7.preference.EditTextPreference; 36 import android.support.v7.preference.ListPreference; 37 import android.support.v7.preference.Preference; 38 import android.support.v7.preference.Preference.OnPreferenceChangeListener; 39 import android.telephony.ServiceState; 40 import android.telephony.SubscriptionManager; 41 import android.telephony.TelephonyManager; 42 import android.text.TextUtils; 43 import android.util.Log; 44 import android.view.KeyEvent; 45 import android.view.Menu; 46 import android.view.MenuInflater; 47 import android.view.MenuItem; 48 import android.view.View; 49 import android.view.View.OnKeyListener; 50 51 import com.android.internal.logging.MetricsProto.MetricsEvent; 52 53 import java.util.HashSet; 54 import java.util.Set; 55 56 public class ApnEditor extends SettingsPreferenceFragment 57 implements OnPreferenceChangeListener, OnKeyListener { 58 59 private final static String TAG = ApnEditor.class.getSimpleName(); 60 61 private final static String SAVED_POS = "pos"; 62 private final static String KEY_AUTH_TYPE = "auth_type"; 63 private final static String KEY_PROTOCOL = "apn_protocol"; 64 private final static String KEY_ROAMING_PROTOCOL = "apn_roaming_protocol"; 65 private final static String KEY_CARRIER_ENABLED = "carrier_enabled"; 66 private final static String KEY_BEARER_MULTI = "bearer_multi"; 67 private final static String KEY_MVNO_TYPE = "mvno_type"; 68 69 private static final int MENU_DELETE = Menu.FIRST; 70 private static final int MENU_SAVE = Menu.FIRST + 1; 71 private static final int MENU_CANCEL = Menu.FIRST + 2; 72 73 private static String sNotSet; 74 private EditTextPreference mName; 75 private EditTextPreference mApn; 76 private EditTextPreference mProxy; 77 private EditTextPreference mPort; 78 private EditTextPreference mUser; 79 private EditTextPreference mServer; 80 private EditTextPreference mPassword; 81 private EditTextPreference mMmsc; 82 private EditTextPreference mMcc; 83 private EditTextPreference mMnc; 84 private EditTextPreference mMmsProxy; 85 private EditTextPreference mMmsPort; 86 private ListPreference mAuthType; 87 private EditTextPreference mApnType; 88 private ListPreference mProtocol; 89 private ListPreference mRoamingProtocol; 90 private SwitchPreference mCarrierEnabled; 91 private MultiSelectListPreference mBearerMulti; 92 private ListPreference mMvnoType; 93 private EditTextPreference mMvnoMatchData; 94 95 private String mCurMnc; 96 private String mCurMcc; 97 98 private Uri mUri; 99 private Cursor mCursor; 100 private boolean mNewApn; 101 private boolean mFirstTime; 102 private int mSubId; 103 private Resources mRes; 104 private TelephonyManager mTelephonyManager; 105 private int mBearerInitialVal = 0; 106 private String mMvnoTypeStr; 107 private String mMvnoMatchDataStr; 108 109 /** 110 * Standard projection for the interesting columns of a normal note. 111 */ 112 private static final String[] sProjection = new String[] { 113 Telephony.Carriers._ID, // 0 114 Telephony.Carriers.NAME, // 1 115 Telephony.Carriers.APN, // 2 116 Telephony.Carriers.PROXY, // 3 117 Telephony.Carriers.PORT, // 4 118 Telephony.Carriers.USER, // 5 119 Telephony.Carriers.SERVER, // 6 120 Telephony.Carriers.PASSWORD, // 7 121 Telephony.Carriers.MMSC, // 8 122 Telephony.Carriers.MCC, // 9 123 Telephony.Carriers.MNC, // 10 124 Telephony.Carriers.NUMERIC, // 11 125 Telephony.Carriers.MMSPROXY,// 12 126 Telephony.Carriers.MMSPORT, // 13 127 Telephony.Carriers.AUTH_TYPE, // 14 128 Telephony.Carriers.TYPE, // 15 129 Telephony.Carriers.PROTOCOL, // 16 130 Telephony.Carriers.CARRIER_ENABLED, // 17 131 Telephony.Carriers.BEARER, // 18 132 Telephony.Carriers.BEARER_BITMASK, // 19 133 Telephony.Carriers.ROAMING_PROTOCOL, // 20 134 Telephony.Carriers.MVNO_TYPE, // 21 135 Telephony.Carriers.MVNO_MATCH_DATA // 22 136 }; 137 138 private static final int ID_INDEX = 0; 139 private static final int NAME_INDEX = 1; 140 private static final int APN_INDEX = 2; 141 private static final int PROXY_INDEX = 3; 142 private static final int PORT_INDEX = 4; 143 private static final int USER_INDEX = 5; 144 private static final int SERVER_INDEX = 6; 145 private static final int PASSWORD_INDEX = 7; 146 private static final int MMSC_INDEX = 8; 147 private static final int MCC_INDEX = 9; 148 private static final int MNC_INDEX = 10; 149 private static final int MMSPROXY_INDEX = 12; 150 private static final int MMSPORT_INDEX = 13; 151 private static final int AUTH_TYPE_INDEX = 14; 152 private static final int TYPE_INDEX = 15; 153 private static final int PROTOCOL_INDEX = 16; 154 private static final int CARRIER_ENABLED_INDEX = 17; 155 private static final int BEARER_INDEX = 18; 156 private static final int BEARER_BITMASK_INDEX = 19; 157 private static final int ROAMING_PROTOCOL_INDEX = 20; 158 private static final int MVNO_TYPE_INDEX = 21; 159 private static final int MVNO_MATCH_DATA_INDEX = 22; 160 161 162 @Override 163 public void onCreate(Bundle icicle) { 164 super.onCreate(icicle); 165 166 addPreferencesFromResource(R.xml.apn_editor); 167 168 sNotSet = getResources().getString(R.string.apn_not_set); 169 mName = (EditTextPreference) findPreference("apn_name"); 170 mApn = (EditTextPreference) findPreference("apn_apn"); 171 mProxy = (EditTextPreference) findPreference("apn_http_proxy"); 172 mPort = (EditTextPreference) findPreference("apn_http_port"); 173 mUser = (EditTextPreference) findPreference("apn_user"); 174 mServer = (EditTextPreference) findPreference("apn_server"); 175 mPassword = (EditTextPreference) findPreference("apn_password"); 176 mMmsProxy = (EditTextPreference) findPreference("apn_mms_proxy"); 177 mMmsPort = (EditTextPreference) findPreference("apn_mms_port"); 178 mMmsc = (EditTextPreference) findPreference("apn_mmsc"); 179 mMcc = (EditTextPreference) findPreference("apn_mcc"); 180 mMnc = (EditTextPreference) findPreference("apn_mnc"); 181 mApnType = (EditTextPreference) findPreference("apn_type"); 182 183 mAuthType = (ListPreference) findPreference(KEY_AUTH_TYPE); 184 mAuthType.setOnPreferenceChangeListener(this); 185 186 mProtocol = (ListPreference) findPreference(KEY_PROTOCOL); 187 mProtocol.setOnPreferenceChangeListener(this); 188 189 mRoamingProtocol = (ListPreference) findPreference(KEY_ROAMING_PROTOCOL); 190 mRoamingProtocol.setOnPreferenceChangeListener(this); 191 192 mCarrierEnabled = (SwitchPreference) findPreference(KEY_CARRIER_ENABLED); 193 194 mBearerMulti = (MultiSelectListPreference) findPreference(KEY_BEARER_MULTI); 195 mBearerMulti.setOnPreferenceChangeListener(this); 196 197 mMvnoType = (ListPreference) findPreference(KEY_MVNO_TYPE); 198 mMvnoType.setOnPreferenceChangeListener(this); 199 mMvnoMatchData = (EditTextPreference) findPreference("mvno_match_data"); 200 201 mRes = getResources(); 202 203 final Intent intent = getIntent(); 204 final String action = intent.getAction(); 205 mSubId = intent.getIntExtra(ApnSettings.SUB_ID, 206 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 207 208 mFirstTime = icicle == null; 209 210 if (action.equals(Intent.ACTION_EDIT)) { 211 Uri uri = intent.getData(); 212 if (!uri.isPathPrefixMatch(Telephony.Carriers.CONTENT_URI)) { 213 Log.e(TAG, "Edit request not for carrier table. Uri: " + uri); 214 finish(); 215 return; 216 } 217 mUri = uri; 218 } else if (action.equals(Intent.ACTION_INSERT)) { 219 if (mFirstTime || icicle.getInt(SAVED_POS) == 0) { 220 Uri uri = intent.getData(); 221 if (!uri.isPathPrefixMatch(Telephony.Carriers.CONTENT_URI)) { 222 Log.e(TAG, "Insert request not for carrier table. Uri: " + uri); 223 finish(); 224 return; 225 } 226 mUri = getContentResolver().insert(uri, new ContentValues()); 227 } else { 228 mUri = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, 229 icicle.getInt(SAVED_POS)); 230 } 231 mNewApn = true; 232 mMvnoTypeStr = intent.getStringExtra(ApnSettings.MVNO_TYPE); 233 mMvnoMatchDataStr = intent.getStringExtra(ApnSettings.MVNO_MATCH_DATA); 234 // If we were unable to create a new note, then just finish 235 // this activity. A RESULT_CANCELED will be sent back to the 236 // original activity if they requested a result. 237 if (mUri == null) { 238 Log.w(TAG, "Failed to insert new telephony provider into " 239 + getIntent().getData()); 240 finish(); 241 return; 242 } 243 244 // The new entry was created, so assume all will end well and 245 // set the result to be returned. 246 setResult(RESULT_OK, (new Intent()).setAction(mUri.toString())); 247 248 } else { 249 finish(); 250 return; 251 } 252 253 mCursor = getActivity().managedQuery(mUri, sProjection, null, null); 254 mCursor.moveToFirst(); 255 256 mTelephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); 257 258 for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); i++) { 259 getPreferenceScreen().getPreference(i).setOnPreferenceChangeListener(this); 260 } 261 262 fillUi(); 263 } 264 265 @Override 266 protected int getMetricsCategory() { 267 return MetricsEvent.APN_EDITOR; 268 } 269 270 @Override 271 public void onResume() { 272 super.onResume(); 273 } 274 275 @Override 276 public void onPause() { 277 super.onPause(); 278 } 279 280 private void fillUi() { 281 if (mFirstTime) { 282 mFirstTime = false; 283 // Fill in all the values from the db in both text editor and summary 284 mName.setText(mCursor.getString(NAME_INDEX)); 285 mApn.setText(mCursor.getString(APN_INDEX)); 286 mProxy.setText(mCursor.getString(PROXY_INDEX)); 287 mPort.setText(mCursor.getString(PORT_INDEX)); 288 mUser.setText(mCursor.getString(USER_INDEX)); 289 mServer.setText(mCursor.getString(SERVER_INDEX)); 290 mPassword.setText(mCursor.getString(PASSWORD_INDEX)); 291 mMmsProxy.setText(mCursor.getString(MMSPROXY_INDEX)); 292 mMmsPort.setText(mCursor.getString(MMSPORT_INDEX)); 293 mMmsc.setText(mCursor.getString(MMSC_INDEX)); 294 mMcc.setText(mCursor.getString(MCC_INDEX)); 295 mMnc.setText(mCursor.getString(MNC_INDEX)); 296 mApnType.setText(mCursor.getString(TYPE_INDEX)); 297 if (mNewApn) { 298 String numeric = mTelephonyManager.getSimOperator(mSubId); 299 // MCC is first 3 chars and then in 2 - 3 chars of MNC 300 if (numeric != null && numeric.length() > 4) { 301 // Country code 302 String mcc = numeric.substring(0, 3); 303 // Network code 304 String mnc = numeric.substring(3); 305 // Auto populate MNC and MCC for new entries, based on what SIM reports 306 mMcc.setText(mcc); 307 mMnc.setText(mnc); 308 mCurMnc = mnc; 309 mCurMcc = mcc; 310 } 311 } 312 int authVal = mCursor.getInt(AUTH_TYPE_INDEX); 313 if (authVal != -1) { 314 mAuthType.setValueIndex(authVal); 315 } else { 316 mAuthType.setValue(null); 317 } 318 319 mProtocol.setValue(mCursor.getString(PROTOCOL_INDEX)); 320 mRoamingProtocol.setValue(mCursor.getString(ROAMING_PROTOCOL_INDEX)); 321 mCarrierEnabled.setChecked(mCursor.getInt(CARRIER_ENABLED_INDEX)==1); 322 mBearerInitialVal = mCursor.getInt(BEARER_INDEX); 323 324 HashSet<String> bearers = new HashSet<String>(); 325 int bearerBitmask = mCursor.getInt(BEARER_BITMASK_INDEX); 326 if (bearerBitmask == 0) { 327 if (mBearerInitialVal == 0) { 328 bearers.add("" + 0); 329 } 330 } else { 331 int i = 1; 332 while (bearerBitmask != 0) { 333 if ((bearerBitmask & 1) == 1) { 334 bearers.add("" + i); 335 } 336 bearerBitmask >>= 1; 337 i++; 338 } 339 } 340 341 if (mBearerInitialVal != 0 && bearers.contains("" + mBearerInitialVal) == false) { 342 // add mBearerInitialVal to bearers 343 bearers.add("" + mBearerInitialVal); 344 } 345 mBearerMulti.setValues(bearers); 346 347 mMvnoType.setValue(mCursor.getString(MVNO_TYPE_INDEX)); 348 mMvnoMatchData.setEnabled(false); 349 mMvnoMatchData.setText(mCursor.getString(MVNO_MATCH_DATA_INDEX)); 350 if (mNewApn && mMvnoTypeStr != null && mMvnoMatchDataStr != null) { 351 mMvnoType.setValue(mMvnoTypeStr); 352 mMvnoMatchData.setText(mMvnoMatchDataStr); 353 } 354 } 355 356 mName.setSummary(checkNull(mName.getText())); 357 mApn.setSummary(checkNull(mApn.getText())); 358 mProxy.setSummary(checkNull(mProxy.getText())); 359 mPort.setSummary(checkNull(mPort.getText())); 360 mUser.setSummary(checkNull(mUser.getText())); 361 mServer.setSummary(checkNull(mServer.getText())); 362 mPassword.setSummary(starify(mPassword.getText())); 363 mMmsProxy.setSummary(checkNull(mMmsProxy.getText())); 364 mMmsPort.setSummary(checkNull(mMmsPort.getText())); 365 mMmsc.setSummary(checkNull(mMmsc.getText())); 366 mMcc.setSummary(checkNull(mMcc.getText())); 367 mMnc.setSummary(checkNull(mMnc.getText())); 368 mApnType.setSummary(checkNull(mApnType.getText())); 369 370 String authVal = mAuthType.getValue(); 371 if (authVal != null) { 372 int authValIndex = Integer.parseInt(authVal); 373 mAuthType.setValueIndex(authValIndex); 374 375 String []values = mRes.getStringArray(R.array.apn_auth_entries); 376 mAuthType.setSummary(values[authValIndex]); 377 } else { 378 mAuthType.setSummary(sNotSet); 379 } 380 381 mProtocol.setSummary( 382 checkNull(protocolDescription(mProtocol.getValue(), mProtocol))); 383 mRoamingProtocol.setSummary( 384 checkNull(protocolDescription(mRoamingProtocol.getValue(), mRoamingProtocol))); 385 mBearerMulti.setSummary( 386 checkNull(bearerMultiDescription(mBearerMulti.getValues()))); 387 mMvnoType.setSummary( 388 checkNull(mvnoDescription(mMvnoType.getValue()))); 389 mMvnoMatchData.setSummary(checkNull(mMvnoMatchData.getText())); 390 // allow user to edit carrier_enabled for some APN 391 boolean ceEditable = getResources().getBoolean(R.bool.config_allow_edit_carrier_enabled); 392 if (ceEditable) { 393 mCarrierEnabled.setEnabled(true); 394 } else { 395 mCarrierEnabled.setEnabled(false); 396 } 397 } 398 399 /** 400 * Returns the UI choice (e.g., "IPv4/IPv6") corresponding to the given 401 * raw value of the protocol preference (e.g., "IPV4V6"). If unknown, 402 * return null. 403 */ 404 private String protocolDescription(String raw, ListPreference protocol) { 405 int protocolIndex = protocol.findIndexOfValue(raw); 406 if (protocolIndex == -1) { 407 return null; 408 } else { 409 String[] values = mRes.getStringArray(R.array.apn_protocol_entries); 410 try { 411 return values[protocolIndex]; 412 } catch (ArrayIndexOutOfBoundsException e) { 413 return null; 414 } 415 } 416 } 417 418 private String bearerDescription(String raw) { 419 int mBearerIndex = mBearerMulti.findIndexOfValue(raw); 420 if (mBearerIndex == -1) { 421 return null; 422 } else { 423 String[] values = mRes.getStringArray(R.array.bearer_entries); 424 try { 425 return values[mBearerIndex]; 426 } catch (ArrayIndexOutOfBoundsException e) { 427 return null; 428 } 429 } 430 } 431 432 private String bearerMultiDescription(Set<String> raw) { 433 String[] values = mRes.getStringArray(R.array.bearer_entries); 434 StringBuilder retVal = new StringBuilder(); 435 boolean first = true; 436 for (String bearer : raw) { 437 int bearerIndex = mBearerMulti.findIndexOfValue(bearer); 438 try { 439 if (first) { 440 retVal.append(values[bearerIndex]); 441 first = false; 442 } else { 443 retVal.append(", " + values[bearerIndex]); 444 } 445 } catch (ArrayIndexOutOfBoundsException e) { 446 // ignore 447 } 448 } 449 String val = retVal.toString(); 450 if (!TextUtils.isEmpty(val)) { 451 return val; 452 } 453 return null; 454 } 455 456 private String mvnoDescription(String newValue) { 457 int mvnoIndex = mMvnoType.findIndexOfValue(newValue); 458 String oldValue = mMvnoType.getValue(); 459 460 if (mvnoIndex == -1) { 461 return null; 462 } else { 463 String[] values = mRes.getStringArray(R.array.mvno_type_entries); 464 mMvnoMatchData.setEnabled(mvnoIndex != 0); 465 if (newValue != null && newValue.equals(oldValue) == false) { 466 if (values[mvnoIndex].equals("SPN")) { 467 mMvnoMatchData.setText(mTelephonyManager.getSimOperatorName()); 468 } else if (values[mvnoIndex].equals("IMSI")) { 469 String numeric = mTelephonyManager.getSimOperator(mSubId); 470 mMvnoMatchData.setText(numeric + "x"); 471 } else if (values[mvnoIndex].equals("GID")) { 472 mMvnoMatchData.setText(mTelephonyManager.getGroupIdLevel1()); 473 } 474 } 475 476 try { 477 return values[mvnoIndex]; 478 } catch (ArrayIndexOutOfBoundsException e) { 479 return null; 480 } 481 } 482 } 483 484 public boolean onPreferenceChange(Preference preference, Object newValue) { 485 String key = preference.getKey(); 486 if (KEY_AUTH_TYPE.equals(key)) { 487 try { 488 int index = Integer.parseInt((String) newValue); 489 mAuthType.setValueIndex(index); 490 491 String[] values = mRes.getStringArray(R.array.apn_auth_entries); 492 mAuthType.setSummary(values[index]); 493 } catch (NumberFormatException e) { 494 return false; 495 } 496 } else if (KEY_PROTOCOL.equals(key)) { 497 String protocol = protocolDescription((String) newValue, mProtocol); 498 if (protocol == null) { 499 return false; 500 } 501 mProtocol.setSummary(protocol); 502 mProtocol.setValue((String) newValue); 503 } else if (KEY_ROAMING_PROTOCOL.equals(key)) { 504 String protocol = protocolDescription((String) newValue, mRoamingProtocol); 505 if (protocol == null) { 506 return false; 507 } 508 mRoamingProtocol.setSummary(protocol); 509 mRoamingProtocol.setValue((String) newValue); 510 } else if (KEY_BEARER_MULTI.equals(key)) { 511 String bearer = bearerMultiDescription((Set<String>) newValue); 512 if (bearer == null) { 513 return false; 514 } 515 mBearerMulti.setValues((Set<String>) newValue); 516 mBearerMulti.setSummary(bearer); 517 } else if (KEY_MVNO_TYPE.equals(key)) { 518 String mvno = mvnoDescription((String) newValue); 519 if (mvno == null) { 520 return false; 521 } 522 mMvnoType.setValue((String) newValue); 523 mMvnoType.setSummary(mvno); 524 } 525 if (preference.equals(mPassword)) { 526 preference.setSummary(starify(newValue != null ? String.valueOf(newValue) : "")); 527 } else if (preference.equals(mCarrierEnabled) || preference.equals(mBearerMulti)) { 528 // do nothing 529 } else { 530 preference.setSummary(checkNull(newValue != null ? String.valueOf(newValue) : null)); 531 } 532 533 return true; 534 } 535 536 @Override 537 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 538 super.onCreateOptionsMenu(menu, inflater); 539 // If it's a new APN, then cancel will delete the new entry in onPause 540 if (!mNewApn) { 541 menu.add(0, MENU_DELETE, 0, R.string.menu_delete) 542 .setIcon(R.drawable.ic_menu_delete); 543 } 544 menu.add(0, MENU_SAVE, 0, R.string.menu_save) 545 .setIcon(android.R.drawable.ic_menu_save); 546 menu.add(0, MENU_CANCEL, 0, R.string.menu_cancel) 547 .setIcon(android.R.drawable.ic_menu_close_clear_cancel); 548 } 549 550 @Override 551 public boolean onOptionsItemSelected(MenuItem item) { 552 switch (item.getItemId()) { 553 case MENU_DELETE: 554 deleteApn(); 555 return true; 556 case MENU_SAVE: 557 if (validateAndSave(false)) { 558 finish(); 559 } 560 return true; 561 case MENU_CANCEL: 562 if (mNewApn) { 563 getContentResolver().delete(mUri, null, null); 564 } 565 finish(); 566 return true; 567 } 568 return super.onOptionsItemSelected(item); 569 } 570 571 @Override 572 public void onViewCreated(View view, Bundle savedInstanceState) { 573 super.onViewCreated(view, savedInstanceState); 574 view.setOnKeyListener(this); 575 } 576 577 public boolean onKey(View v, int keyCode, KeyEvent event) { 578 if (event.getAction() != KeyEvent.ACTION_DOWN) return false; 579 switch (keyCode) { 580 case KeyEvent.KEYCODE_BACK: { 581 if (validateAndSave(false)) { 582 finish(); 583 } 584 return true; 585 } 586 } 587 return false; 588 } 589 590 @Override 591 public void onSaveInstanceState(Bundle icicle) { 592 super.onSaveInstanceState(icicle); 593 if (validateAndSave(true)) { 594 icicle.putInt(SAVED_POS, mCursor.getInt(ID_INDEX)); 595 } 596 } 597 598 /** 599 * Check the key fields' validity and save if valid. 600 * @param force save even if the fields are not valid, if the app is 601 * being suspended 602 * @return true if the data was saved 603 */ 604 private boolean validateAndSave(boolean force) { 605 String name = checkNotSet(mName.getText()); 606 String apn = checkNotSet(mApn.getText()); 607 String mcc = checkNotSet(mMcc.getText()); 608 String mnc = checkNotSet(mMnc.getText()); 609 610 if (getErrorMsg() != null && !force) { 611 ErrorDialog.showError(this); 612 return false; 613 } 614 615 if (!mCursor.moveToFirst()) { 616 Log.w(TAG, 617 "Could not go to the first row in the Cursor when saving data."); 618 return false; 619 } 620 621 // If it's a new APN and a name or apn haven't been entered, then erase the entry 622 if (force && mNewApn && name.length() < 1 && apn.length() < 1) { 623 getContentResolver().delete(mUri, null, null); 624 return false; 625 } 626 627 ContentValues values = new ContentValues(); 628 629 // Add a dummy name "Untitled", if the user exits the screen without adding a name but 630 // entered other information worth keeping. 631 values.put(Telephony.Carriers.NAME, 632 name.length() < 1 ? getResources().getString(R.string.untitled_apn) : name); 633 values.put(Telephony.Carriers.APN, apn); 634 values.put(Telephony.Carriers.PROXY, checkNotSet(mProxy.getText())); 635 values.put(Telephony.Carriers.PORT, checkNotSet(mPort.getText())); 636 values.put(Telephony.Carriers.MMSPROXY, checkNotSet(mMmsProxy.getText())); 637 values.put(Telephony.Carriers.MMSPORT, checkNotSet(mMmsPort.getText())); 638 values.put(Telephony.Carriers.USER, checkNotSet(mUser.getText())); 639 values.put(Telephony.Carriers.SERVER, checkNotSet(mServer.getText())); 640 values.put(Telephony.Carriers.PASSWORD, checkNotSet(mPassword.getText())); 641 values.put(Telephony.Carriers.MMSC, checkNotSet(mMmsc.getText())); 642 643 String authVal = mAuthType.getValue(); 644 if (authVal != null) { 645 values.put(Telephony.Carriers.AUTH_TYPE, Integer.parseInt(authVal)); 646 } 647 648 values.put(Telephony.Carriers.PROTOCOL, checkNotSet(mProtocol.getValue())); 649 values.put(Telephony.Carriers.ROAMING_PROTOCOL, checkNotSet(mRoamingProtocol.getValue())); 650 651 values.put(Telephony.Carriers.TYPE, checkNotSet(mApnType.getText())); 652 653 values.put(Telephony.Carriers.MCC, mcc); 654 values.put(Telephony.Carriers.MNC, mnc); 655 656 values.put(Telephony.Carriers.NUMERIC, mcc + mnc); 657 658 if (mCurMnc != null && mCurMcc != null) { 659 if (mCurMnc.equals(mnc) && mCurMcc.equals(mcc)) { 660 values.put(Telephony.Carriers.CURRENT, 1); 661 } 662 } 663 664 Set<String> bearerSet = mBearerMulti.getValues(); 665 int bearerBitmask = 0; 666 for (String bearer : bearerSet) { 667 if (Integer.parseInt(bearer) == 0) { 668 bearerBitmask = 0; 669 break; 670 } else { 671 bearerBitmask |= ServiceState.getBitmaskForTech(Integer.parseInt(bearer)); 672 } 673 } 674 values.put(Telephony.Carriers.BEARER_BITMASK, bearerBitmask); 675 676 int bearerVal; 677 if (bearerBitmask == 0 || mBearerInitialVal == 0) { 678 bearerVal = 0; 679 } else if (ServiceState.bitmaskHasTech(bearerBitmask, mBearerInitialVal)) { 680 bearerVal = mBearerInitialVal; 681 } else { 682 // bearer field was being used but bitmask has changed now and does not include the 683 // initial bearer value -- setting bearer to 0 but maybe better behavior is to choose a 684 // random tech from the new bitmask?? 685 bearerVal = 0; 686 } 687 values.put(Telephony.Carriers.BEARER, bearerVal); 688 689 values.put(Telephony.Carriers.MVNO_TYPE, checkNotSet(mMvnoType.getValue())); 690 values.put(Telephony.Carriers.MVNO_MATCH_DATA, checkNotSet(mMvnoMatchData.getText())); 691 692 values.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled.isChecked() ? 1 : 0); 693 getContentResolver().update(mUri, values, null, null); 694 695 return true; 696 } 697 698 private String getErrorMsg() { 699 String errorMsg = null; 700 701 String name = checkNotSet(mName.getText()); 702 String apn = checkNotSet(mApn.getText()); 703 String mcc = checkNotSet(mMcc.getText()); 704 String mnc = checkNotSet(mMnc.getText()); 705 706 if (name.length() < 1) { 707 errorMsg = mRes.getString(R.string.error_name_empty); 708 } else if (apn.length() < 1) { 709 errorMsg = mRes.getString(R.string.error_apn_empty); 710 } else if (mcc.length() != 3) { 711 errorMsg = mRes.getString(R.string.error_mcc_not3); 712 } else if ((mnc.length() & 0xFFFE) != 2) { 713 errorMsg = mRes.getString(R.string.error_mnc_not23); 714 } 715 716 return errorMsg; 717 } 718 719 private void deleteApn() { 720 getContentResolver().delete(mUri, null, null); 721 finish(); 722 } 723 724 private String starify(String value) { 725 if (value == null || value.length() == 0) { 726 return sNotSet; 727 } else { 728 char[] password = new char[value.length()]; 729 for (int i = 0; i < password.length; i++) { 730 password[i] = '*'; 731 } 732 return new String(password); 733 } 734 } 735 736 private String checkNull(String value) { 737 if (value == null || value.length() == 0) { 738 return sNotSet; 739 } else { 740 return value; 741 } 742 } 743 744 private String checkNotSet(String value) { 745 if (value == null || value.equals(sNotSet)) { 746 return ""; 747 } else { 748 return value; 749 } 750 } 751 752 public static class ErrorDialog extends DialogFragment { 753 754 public static void showError(ApnEditor editor) { 755 ErrorDialog dialog = new ErrorDialog(); 756 dialog.setTargetFragment(editor, 0); 757 dialog.show(editor.getFragmentManager(), "error"); 758 } 759 760 @Override 761 public Dialog onCreateDialog(Bundle savedInstanceState) { 762 String msg = ((ApnEditor) getTargetFragment()).getErrorMsg(); 763 764 return new AlertDialog.Builder(getContext()) 765 .setTitle(R.string.error_title) 766 .setPositiveButton(android.R.string.ok, null) 767 .setMessage(msg) 768 .create(); 769 } 770 } 771 772 } 773