/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings; import android.app.AlertDialog; import android.app.Dialog; import android.content.ContentUris; import android.content.ContentValues; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.preference.EditTextPreference; import android.preference.ListPreference; import android.preference.MultiSelectListPreference; import android.preference.Preference; import android.preference.SwitchPreference; import android.provider.Telephony; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import com.android.internal.logging.MetricsLogger; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; public class ApnEditor extends InstrumentedPreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener, Preference.OnPreferenceChangeListener { private final static String TAG = ApnEditor.class.getSimpleName(); private final static String SAVED_POS = "pos"; private final static String KEY_AUTH_TYPE = "auth_type"; private final static String KEY_PROTOCOL = "apn_protocol"; private final static String KEY_ROAMING_PROTOCOL = "apn_roaming_protocol"; private final static String KEY_CARRIER_ENABLED = "carrier_enabled"; private final static String KEY_BEARER_MULTI = "bearer_multi"; private final static String KEY_MVNO_TYPE = "mvno_type"; private final static String PROTOCOL_IPV4V6= "IPV4V6"; private static final int MENU_DELETE = Menu.FIRST; private static final int MENU_SAVE = Menu.FIRST + 1; private static final int MENU_CANCEL = Menu.FIRST + 2; private static final int ERROR_DIALOG_ID = 0; private static final int DUPLICATE_DIALOG_ID = 1; private static String sNotSet; private EditTextPreference mName; private EditTextPreference mApn; private EditTextPreference mProxy; private EditTextPreference mPort; private EditTextPreference mUser; private EditTextPreference mServer; private EditTextPreference mPassword; private EditTextPreference mMmsc; private EditTextPreference mMcc; private EditTextPreference mMnc; private EditTextPreference mMmsProxy; private EditTextPreference mMmsPort; private ListPreference mAuthType; private EditTextPreference mApnType; private ListPreference mProtocol; private ListPreference mRoamingProtocol; private SwitchPreference mCarrierEnabled; private MultiSelectListPreference mBearerMulti; private ListPreference mMvnoType; private EditTextPreference mMvnoMatchData; private EditTextPreference mPppNumber; private String mCurMnc; private String mCurMcc; private boolean mDisableEditor = false; private Uri mUri; private Cursor mCursor; private boolean mNewApn; private boolean mFirstTime; private int mSubId; private Resources mRes; private TelephonyManager mTelephonyManager; private int mBearerInitialVal = 0; private String mMvnoTypeStr; private String mMvnoMatchDataStr; /** * Standard projection for the interesting columns of a normal note. */ private static final String[] sProjection = new String[] { Telephony.Carriers._ID, // 0 Telephony.Carriers.NAME, // 1 Telephony.Carriers.APN, // 2 Telephony.Carriers.PROXY, // 3 Telephony.Carriers.PORT, // 4 Telephony.Carriers.USER, // 5 Telephony.Carriers.SERVER, // 6 Telephony.Carriers.PASSWORD, // 7 Telephony.Carriers.MMSC, // 8 Telephony.Carriers.MCC, // 9 Telephony.Carriers.MNC, // 10 Telephony.Carriers.NUMERIC, // 11 Telephony.Carriers.MMSPROXY,// 12 Telephony.Carriers.MMSPORT, // 13 Telephony.Carriers.AUTH_TYPE, // 14 Telephony.Carriers.TYPE, // 15 Telephony.Carriers.PROTOCOL, // 16 Telephony.Carriers.CARRIER_ENABLED, // 17 Telephony.Carriers.BEARER, // 18 Telephony.Carriers.BEARER_BITMASK, // 19 Telephony.Carriers.ROAMING_PROTOCOL, // 20 Telephony.Carriers.MVNO_TYPE, // 21 Telephony.Carriers.MVNO_MATCH_DATA, // 22 "ppp_number" // 23 }; private static final int ID_INDEX = 0; private static final int NAME_INDEX = 1; private static final int APN_INDEX = 2; private static final int PROXY_INDEX = 3; private static final int PORT_INDEX = 4; private static final int USER_INDEX = 5; private static final int SERVER_INDEX = 6; private static final int PASSWORD_INDEX = 7; private static final int MMSC_INDEX = 8; private static final int MCC_INDEX = 9; private static final int MNC_INDEX = 10; private static final int MMSPROXY_INDEX = 12; private static final int MMSPORT_INDEX = 13; private static final int AUTH_TYPE_INDEX = 14; private static final int TYPE_INDEX = 15; private static final int PROTOCOL_INDEX = 16; private static final int CARRIER_ENABLED_INDEX = 17; private static final int BEARER_INDEX = 18; private static final int BEARER_BITMASK_INDEX = 19; private static final int ROAMING_PROTOCOL_INDEX = 20; private static final int MVNO_TYPE_INDEX = 21; private static final int MVNO_MATCH_DATA_INDEX = 22; private static final int PPP_NUMBER_INDEX = 23; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); addPreferencesFromResource(R.xml.apn_editor); sNotSet = getResources().getString(R.string.apn_not_set); mName = (EditTextPreference) findPreference("apn_name"); mApn = (EditTextPreference) findPreference("apn_apn"); mProxy = (EditTextPreference) findPreference("apn_http_proxy"); mPort = (EditTextPreference) findPreference("apn_http_port"); mUser = (EditTextPreference) findPreference("apn_user"); mServer = (EditTextPreference) findPreference("apn_server"); mPassword = (EditTextPreference) findPreference("apn_password"); mMmsProxy = (EditTextPreference) findPreference("apn_mms_proxy"); mMmsPort = (EditTextPreference) findPreference("apn_mms_port"); mMmsc = (EditTextPreference) findPreference("apn_mmsc"); mMcc = (EditTextPreference) findPreference("apn_mcc"); mMnc = (EditTextPreference) findPreference("apn_mnc"); mApnType = (EditTextPreference) findPreference("apn_type"); mPppNumber = (EditTextPreference) findPreference("apn_ppp_number"); mAuthType = (ListPreference) findPreference(KEY_AUTH_TYPE); mAuthType.setOnPreferenceChangeListener(this); mProtocol = (ListPreference) findPreference(KEY_PROTOCOL); mProtocol.setOnPreferenceChangeListener(this); mRoamingProtocol = (ListPreference) findPreference(KEY_ROAMING_PROTOCOL); mRoamingProtocol.setOnPreferenceChangeListener(this); mCarrierEnabled = (SwitchPreference) findPreference(KEY_CARRIER_ENABLED); mBearerMulti = (MultiSelectListPreference) findPreference(KEY_BEARER_MULTI); mBearerMulti.setOnPreferenceChangeListener(this); mMvnoType = (ListPreference) findPreference(KEY_MVNO_TYPE); mMvnoType.setOnPreferenceChangeListener(this); mMvnoMatchData = (EditTextPreference) findPreference("mvno_match_data"); mRes = getResources(); final Intent intent = getIntent(); final String action = intent.getAction(); mSubId = intent.getIntExtra(ApnSettings.SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); mDisableEditor = intent.getBooleanExtra("DISABLE_EDITOR", false); if (mDisableEditor) { getPreferenceScreen().setEnabled(false); Log.d(TAG, "ApnEditor form is disabled."); } mFirstTime = icicle == null; if (action.equals(Intent.ACTION_EDIT)) { mUri = intent.getData(); } else if (action.equals(Intent.ACTION_INSERT)) { if (mFirstTime || icicle.getInt(SAVED_POS) == 0) { ContentValues values = new ContentValues(); values.put(Telephony.Carriers.PROTOCOL, PROTOCOL_IPV4V6); values.put(Telephony.Carriers.ROAMING_PROTOCOL, PROTOCOL_IPV4V6); mUri = getContentResolver().insert(intent.getData(), values); } else { mUri = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, icicle.getInt(SAVED_POS)); } mNewApn = true; mMvnoTypeStr = intent.getStringExtra(ApnSettings.MVNO_TYPE); mMvnoMatchDataStr = intent.getStringExtra(ApnSettings.MVNO_MATCH_DATA); // If we were unable to create a new note, then just finish // this activity. A RESULT_CANCELED will be sent back to the // original activity if they requested a result. if (mUri == null) { Log.w(TAG, "Failed to insert new telephony provider into " + getIntent().getData()); finish(); return; } // The new entry was created, so assume all will end well and // set the result to be returned. setResult(RESULT_OK, (new Intent()).setAction(mUri.toString())); } else { finish(); return; } mCursor = managedQuery(mUri, sProjection, null, null); mCursor.moveToFirst(); mTelephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); fillUi(); } @Override protected int getMetricsCategory() { return MetricsLogger.APN_EDITOR; } @Override public void onResume() { super.onResume(); getPreferenceScreen().getSharedPreferences() .registerOnSharedPreferenceChangeListener(this); } @Override public void onPause() { getPreferenceScreen().getSharedPreferences() .unregisterOnSharedPreferenceChangeListener(this); super.onPause(); } private void fillUi() { if (mFirstTime) { mFirstTime = false; String numeric = mTelephonyManager.getIccOperatorNumericForData(mSubId); // Fill in all the values from the db in both text editor and summary mName.setText(mCursor.getString(NAME_INDEX)); mApn.setText(mCursor.getString(APN_INDEX)); mProxy.setText(mCursor.getString(PROXY_INDEX)); mPort.setText(mCursor.getString(PORT_INDEX)); mUser.setText(mCursor.getString(USER_INDEX)); mServer.setText(mCursor.getString(SERVER_INDEX)); mPassword.setText(mCursor.getString(PASSWORD_INDEX)); mMmsProxy.setText(mCursor.getString(MMSPROXY_INDEX)); mMmsPort.setText(mCursor.getString(MMSPORT_INDEX)); mMmsc.setText(mCursor.getString(MMSC_INDEX)); mMcc.setText(mCursor.getString(MCC_INDEX)); mMnc.setText(mCursor.getString(MNC_INDEX)); mApnType.setText(mCursor.getString(TYPE_INDEX)); if (mNewApn) { // MCC is first 3 chars and then in 2 - 3 chars of MNC if (numeric != null && numeric.length() > 4) { // Country code String mcc = numeric.substring(0, 3); // Network code String mnc = numeric.substring(3); // Auto populate MNC and MCC for new entries, based on what SIM reports mMcc.setText(mcc); mMnc.setText(mnc); mCurMnc = mnc; mCurMcc = mcc; } mApnType.setText(checkNull(getString(R.string.config_default_new_apn_type))); } int authVal = mCursor.getInt(AUTH_TYPE_INDEX); if (authVal != -1) { mAuthType.setValueIndex(authVal); } else { mAuthType.setValue(null); } mProtocol.setValue(mCursor.getString(PROTOCOL_INDEX)); mRoamingProtocol.setValue(mCursor.getString(ROAMING_PROTOCOL_INDEX)); mCarrierEnabled.setChecked(mCursor.getInt(CARRIER_ENABLED_INDEX)==1); mBearerInitialVal = mCursor.getInt(BEARER_INDEX); HashSet bearers = new HashSet(); int bearerBitmask = mCursor.getInt(BEARER_BITMASK_INDEX); if (bearerBitmask == 0) { if (mBearerInitialVal == 0) { bearers.add("" + 0); } } else { int i = 1; while (bearerBitmask != 0) { if ((bearerBitmask & 1) == 1) { bearers.add("" + i); } bearerBitmask >>= 1; i++; } } if (mBearerInitialVal != 0 && bearers.contains("" + mBearerInitialVal) == false) { // add mBearerInitialVal to bearers bearers.add("" + mBearerInitialVal); } mBearerMulti.setValues(bearers); mMvnoType.setValue(mCursor.getString(MVNO_TYPE_INDEX)); mMvnoMatchData.setEnabled(false); mMvnoMatchData.setText(mCursor.getString(MVNO_MATCH_DATA_INDEX)); if (mNewApn && mMvnoTypeStr != null && mMvnoMatchDataStr != null) { mMvnoType.setValue(mMvnoTypeStr); mMvnoMatchData.setText(mMvnoMatchDataStr); } String pppNumber = mCursor.getString(PPP_NUMBER_INDEX); mPppNumber.setText(pppNumber); if (pppNumber == null) { if (!mNewApn) { getPreferenceScreen().removePreference(mPppNumber); } else if (getResources().getBoolean(R.bool.config_ppp_enabled)) { getPreferenceScreen().removePreference(mPppNumber); } } } mName.setSummary(checkNull(mName.getText())); mApn.setSummary(checkNull(mApn.getText())); mProxy.setSummary(checkNull(mProxy.getText())); mPort.setSummary(checkNull(mPort.getText())); mUser.setSummary(checkNull(mUser.getText())); mServer.setSummary(checkNull(mServer.getText())); mPassword.setSummary(starify(mPassword.getText())); mMmsProxy.setSummary(checkNull(mMmsProxy.getText())); mMmsPort.setSummary(checkNull(mMmsPort.getText())); mMmsc.setSummary(checkNull(mMmsc.getText())); mMcc.setSummary(checkNull(mMcc.getText())); mMnc.setSummary(checkNull(mMnc.getText())); mApnType.setSummary(checkNull(mApnType.getText())); String pppNumber = mPppNumber.getText(); if (pppNumber != null) { // Remove this preference if PPP number is not present // in the APN settings mPppNumber.setSummary(checkNull(pppNumber)); } String authVal = mAuthType.getValue(); if (authVal != null) { int authValIndex = Integer.parseInt(authVal); mAuthType.setValueIndex(authValIndex); String []values = mRes.getStringArray(R.array.apn_auth_entries); mAuthType.setSummary(values[authValIndex]); } else { mAuthType.setSummary(sNotSet); } mProtocol.setSummary( checkNull(protocolDescription(mProtocol.getValue(), mProtocol))); mRoamingProtocol.setSummary( checkNull(protocolDescription(mRoamingProtocol.getValue(), mRoamingProtocol))); mBearerMulti.setSummary( checkNull(bearerMultiDescription(mBearerMulti.getValues()))); mMvnoType.setSummary( checkNull(mvnoDescription(mMvnoType.getValue()))); mMvnoMatchData.setSummary(checkNull(mMvnoMatchData.getText())); // allow user to edit carrier_enabled for some APN boolean ceEditable = getResources().getBoolean(R.bool.config_allow_edit_carrier_enabled); if (ceEditable) { mCarrierEnabled.setEnabled(true); } else { mCarrierEnabled.setEnabled(false); } } /** * Returns the UI choice (e.g., "IPv4/IPv6") corresponding to the given * raw value of the protocol preference (e.g., "IPV4V6"). If unknown, * return null. */ private String protocolDescription(String raw, ListPreference protocol) { int protocolIndex = protocol.findIndexOfValue(raw); if (protocolIndex == -1) { return null; } else { String[] values = mRes.getStringArray(R.array.apn_protocol_entries); try { return values[protocolIndex]; } catch (ArrayIndexOutOfBoundsException e) { return null; } } } private String bearerDescription(String raw) { int mBearerIndex = mBearerMulti.findIndexOfValue(raw); if (mBearerIndex == -1) { return null; } else { String[] values = mRes.getStringArray(R.array.bearer_entries); try { return values[mBearerIndex]; } catch (ArrayIndexOutOfBoundsException e) { return null; } } } private String bearerMultiDescription(Set raw) { String[] values = mRes.getStringArray(R.array.bearer_entries); StringBuilder retVal = new StringBuilder(); boolean first = true; for (String bearer : raw) { int bearerIndex = mBearerMulti.findIndexOfValue(bearer); try { if (first) { retVal.append(values[bearerIndex]); first = false; } else { retVal.append(", " + values[bearerIndex]); } } catch (ArrayIndexOutOfBoundsException e) { // ignore } } String val = retVal.toString(); if (!TextUtils.isEmpty(val)) { return val; } return null; } private String mvnoDescription(String newValue) { int mvnoIndex = mMvnoType.findIndexOfValue(newValue); String oldValue = mMvnoType.getValue(); if (mvnoIndex == -1) { return null; } else { String[] values = mRes.getStringArray(R.array.mvno_type_entries); if (values[mvnoIndex].equals("None")) { mMvnoMatchData.setEnabled(false); } else { mMvnoMatchData.setEnabled(true); } if (newValue != null && newValue.equals(oldValue) == false) { if (values[mvnoIndex].equals("SPN")) { mMvnoMatchData.setText(mTelephonyManager.getSimOperatorName()); } else if (values[mvnoIndex].equals("IMSI")) { String numeric = mTelephonyManager.getIccOperatorNumericForData(mSubId); mMvnoMatchData.setText(numeric + "x"); } else if (values[mvnoIndex].equals("GID")) { mMvnoMatchData.setText(mTelephonyManager.getGroupIdLevel1()); } } try { return values[mvnoIndex]; } catch (ArrayIndexOutOfBoundsException e) { return null; } } } public boolean onPreferenceChange(Preference preference, Object newValue) { String key = preference.getKey(); if (KEY_AUTH_TYPE.equals(key)) { try { int index = Integer.parseInt((String) newValue); mAuthType.setValueIndex(index); String []values = mRes.getStringArray(R.array.apn_auth_entries); mAuthType.setSummary(values[index]); } catch (NumberFormatException e) { return false; } } else if (KEY_PROTOCOL.equals(key)) { String protocol = protocolDescription((String) newValue, mProtocol); if (protocol == null) { return false; } mProtocol.setSummary(protocol); mProtocol.setValue((String) newValue); } else if (KEY_ROAMING_PROTOCOL.equals(key)) { String protocol = protocolDescription((String) newValue, mRoamingProtocol); if (protocol == null) { return false; } mRoamingProtocol.setSummary(protocol); mRoamingProtocol.setValue((String) newValue); } else if (KEY_BEARER_MULTI.equals(key)) { String bearer = bearerMultiDescription((Set) newValue); if (bearer == null) { return false; } mBearerMulti.setValues((Set) newValue); mBearerMulti.setSummary(bearer); } else if (KEY_MVNO_TYPE.equals(key)) { String mvno = mvnoDescription((String) newValue); if (mvno == null) { return false; } mMvnoType.setValue((String) newValue); mMvnoType.setSummary(mvno); } return true; } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); if (mDisableEditor) { Log.d(TAG, "Form is disabled. Do not create the options menu."); return true; } // If it's a new APN, then cancel will delete the new entry in onPause if (!mNewApn) { menu.add(0, MENU_DELETE, 0, R.string.menu_delete) .setIcon(R.drawable.ic_menu_delete); } menu.add(0, MENU_SAVE, 0, R.string.menu_save) .setIcon(android.R.drawable.ic_menu_save); menu.add(0, MENU_CANCEL, 0, R.string.menu_cancel) .setIcon(android.R.drawable.ic_menu_close_clear_cancel); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_DELETE: deleteApn(); return true; case MENU_SAVE: if (validateAndSave(false)) { finish(); } return true; case MENU_CANCEL: if (mNewApn) { getContentResolver().delete(mUri, null, null); } finish(); return true; } return super.onOptionsItemSelected(item); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: { if (validateAndSave(false)) { finish(); } return true; } } return super.onKeyDown(keyCode, event); } @Override protected void onSaveInstanceState(Bundle icicle) { super.onSaveInstanceState(icicle); if (validateAndSave(true)) { icicle.putInt(SAVED_POS, mCursor.getInt(ID_INDEX)); } } /** * Check the key fields' validity and save if valid. * @param force save even if the fields are not valid, if the app is * being suspended * @return true if the data was saved */ private boolean validateAndSave(boolean force) { // If the form is not editable, do nothing and return. if (mDisableEditor){ Log.d(TAG, "Form is disabled. Nothing to save."); return true; } String name = checkNotSet(mName.getText()); String apn = checkNotSet(mApn.getText()); String mcc = checkNotSet(mMcc.getText()); String mnc = checkNotSet(mMnc.getText()); if (getErrorMsg() != null && !force) { showDialog(ERROR_DIALOG_ID); return false; } if (!mCursor.moveToFirst()) { Log.w(TAG, "Could not go to the first row in the Cursor when saving data."); return false; } // If it's a new APN and a name or apn haven't been entered, then erase the entry if (force && mNewApn && name.length() < 1 && apn.length() < 1) { getContentResolver().delete(mUri, null, null); return false; } ContentValues values = new ContentValues(); // Add a dummy name "Untitled", if the user exits the screen without adding a name but // entered other information worth keeping. values.put(Telephony.Carriers.NAME, name.length() < 1 ? getResources().getString(R.string.untitled_apn) : name); values.put(Telephony.Carriers.APN, apn); values.put(Telephony.Carriers.PROXY, checkNotSet(mProxy.getText())); values.put(Telephony.Carriers.PORT, checkNotSet(mPort.getText())); values.put(Telephony.Carriers.MMSPROXY, checkNotSet(mMmsProxy.getText())); values.put(Telephony.Carriers.MMSPORT, checkNotSet(mMmsPort.getText())); values.put(Telephony.Carriers.USER, checkNotSet(mUser.getText())); values.put(Telephony.Carriers.SERVER, checkNotSet(mServer.getText())); values.put(Telephony.Carriers.PASSWORD, checkNotSet(mPassword.getText())); values.put(Telephony.Carriers.MMSC, checkNotSet(mMmsc.getText())); String authVal = mAuthType.getValue(); if (authVal != null) { values.put(Telephony.Carriers.AUTH_TYPE, Integer.parseInt(authVal)); } values.put(Telephony.Carriers.PROTOCOL, checkNotSet(mProtocol.getValue())); values.put(Telephony.Carriers.ROAMING_PROTOCOL, checkNotSet(mRoamingProtocol.getValue())); values.put(Telephony.Carriers.TYPE, checkNotSet(mApnType.getText())); values.put(Telephony.Carriers.MCC, mcc); values.put(Telephony.Carriers.MNC, mnc); values.put(Telephony.Carriers.NUMERIC, mcc + mnc); String pppNumber = mPppNumber.getText(); if (pppNumber != null) { values.put(getResources().getString(R.string.ppp_number), pppNumber); } if (mCurMnc != null && mCurMcc != null) { if (mCurMnc.equals(mnc) && mCurMcc.equals(mcc)) { values.put(Telephony.Carriers.CURRENT, 1); } } Set bearerSet = mBearerMulti.getValues(); int bearerBitmask = 0; for (String bearer : bearerSet) { if (Integer.parseInt(bearer) == 0) { bearerBitmask = 0; break; } else { bearerBitmask |= ServiceState.getBitmaskForTech(Integer.parseInt(bearer)); } } values.put(Telephony.Carriers.BEARER_BITMASK, bearerBitmask); int bearerVal; if (bearerBitmask == 0 || mBearerInitialVal == 0) { bearerVal = 0; } else if (ServiceState.bitmaskHasTech(bearerBitmask, mBearerInitialVal)) { bearerVal = mBearerInitialVal; } else { // bearer field was being used but bitmask has changed now and does not include the // initial bearer value -- setting bearer to 0 but maybe better behavior is to choose a // random tech from the new bitmask?? bearerVal = 0; } values.put(Telephony.Carriers.BEARER, bearerVal); values.put(Telephony.Carriers.MVNO_TYPE, checkNotSet(mMvnoType.getValue())); values.put(Telephony.Carriers.MVNO_MATCH_DATA, checkNotSet(mMvnoMatchData.getText())); values.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled.isChecked() ? 1 : 0); if (isDuplicate(values)) { showDialog(DUPLICATE_DIALOG_ID); return false; } getContentResolver().update(mUri, values, null, null); return true; } private boolean isDuplicate(ContentValues row) { if (!getResources().getBoolean(R.bool.config_enable_duplicate_apn_checking)) { return false; } final Set keys = row.keySet(); StringBuilder queryBuilder = new StringBuilder(); List selectionArgsList = new ArrayList<>(); final Iterator iterator = keys.iterator(); while (iterator.hasNext()) { final String key = iterator.next(); if (!keyForDuplicateCheck(key) || row.getAsString(key).isEmpty()) { // Skip keys which don't interest us for the duplicate query. // Or if the user hasn't yet filled a field in (empty value), skip it. continue; } queryBuilder.append(key); queryBuilder.append("=?"); queryBuilder.append(" AND "); selectionArgsList.add(row.getAsString(key)); } // remove extra AND at the end queryBuilder.delete(queryBuilder.length() - " AND ".length(), queryBuilder.length()); String[] selectionArgs = new String[selectionArgsList.size()]; selectionArgsList.toArray(selectionArgs); try (Cursor query = getContentResolver().query(Telephony.Carriers.CONTENT_URI, sProjection, queryBuilder.toString(), selectionArgs, null)) { return query.getCount() > (mNewApn ? 0 : 1); } catch (Exception e) { Log.e(TAG, "error querying for duplicates", e); return false; } } /** * Helper method to decide what columns should be considered valid when checking for * potential duplicate APNs before allowing the user to add a new one. * * @param key the column of the row we want to check * @return whether to include this key-value pair in the duplicate query */ private static boolean keyForDuplicateCheck(String key) { switch (key) { case Telephony.Carriers.APN: case Telephony.Carriers.MMSPROXY: case Telephony.Carriers.MMSPORT: case Telephony.Carriers.MMSC: case Telephony.Carriers.TYPE: case Telephony.Carriers.MCC: case Telephony.Carriers.MNC: case Telephony.Carriers.NUMERIC: return true; default: return false; } } private String getErrorMsg() { String errorMsg = null; String name = checkNotSet(mName.getText()); String apn = checkNotSet(mApn.getText()); String mcc = checkNotSet(mMcc.getText()); String mnc = checkNotSet(mMnc.getText()); if (name.length() < 1) { errorMsg = mRes.getString(R.string.error_name_empty); } else if (apn.length() < 1) { errorMsg = mRes.getString(R.string.error_apn_empty); } else if (mcc.length() != 3) { errorMsg = mRes.getString(R.string.error_mcc_not3); } else if ((mnc.length() & 0xFFFE) != 2) { errorMsg = mRes.getString(R.string.error_mnc_not23); } return errorMsg; } @Override protected Dialog onCreateDialog(int id) { if (id == ERROR_DIALOG_ID) { String msg = getErrorMsg(); return new AlertDialog.Builder(this) .setTitle(R.string.error_title) .setPositiveButton(android.R.string.ok, null) .setMessage(msg) .create(); } else if (id == DUPLICATE_DIALOG_ID) { return new AlertDialog.Builder(this) .setTitle(R.string.duplicate_apn_error_title) .setPositiveButton(android.R.string.ok, null) .setMessage(getString(R.string.duplicate_apn_error_message)) .create(); } return super.onCreateDialog(id); } @Override protected void onPrepareDialog(int id, Dialog dialog) { super.onPrepareDialog(id, dialog); if (id == ERROR_DIALOG_ID) { String msg = getErrorMsg(); if (msg != null) { ((AlertDialog)dialog).setMessage(msg); } } } private void deleteApn() { getContentResolver().delete(mUri, null, null); finish(); } private String starify(String value) { if (value == null || value.length() == 0) { return sNotSet; } else { char[] password = new char[value.length()]; for (int i = 0; i < password.length; i++) { password[i] = '*'; } return new String(password); } } private String checkNull(String value) { if (value == null || value.length() == 0) { return sNotSet; } else { return value; } } private String checkNotSet(String value) { if (value == null || value.equals(sNotSet)) { return ""; } else { return value; } } public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { Preference pref = findPreference(key); if (pref != null) { if (pref.equals(mPassword)){ pref.setSummary(starify(sharedPreferences.getString(key, ""))); } else if (pref.equals(mCarrierEnabled) || pref.equals(mBearerMulti)) { // do nothing } else { pref.setSummary(checkNull(sharedPreferences.getString(key, ""))); } } } }