/* * Copyright (C) 2015 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.messaging.ui.appsettings; import android.app.AlertDialog; import android.app.Dialog; import android.content.ContentValues; import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.AsyncTask; import android.os.Bundle; import android.preference.EditTextPreference; import android.preference.Preference; import android.preference.PreferenceFragment; import android.provider.Telephony; import android.support.v4.app.NavUtils; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import com.android.messaging.R; import com.android.messaging.datamodel.data.ParticipantData; import com.android.messaging.sms.ApnDatabase; import com.android.messaging.sms.BugleApnSettingsLoader; import com.android.messaging.ui.BugleActionBarActivity; import com.android.messaging.ui.UIIntents; import com.android.messaging.util.PhoneUtils; public class ApnEditorActivity extends BugleActionBarActivity { private static final int ERROR_DIALOG_ID = 0; private static final String ERROR_MESSAGE_KEY = "error_msg"; private ApnEditorFragment mApnEditorFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getSupportActionBar().setDisplayHomeAsUpEnabled(true); // Display the fragment as the main content. mApnEditorFragment = new ApnEditorFragment(); mApnEditorFragment.setSubId(getIntent().getIntExtra(UIIntents.UI_INTENT_EXTRA_SUB_ID, ParticipantData.DEFAULT_SELF_SUB_ID)); getFragmentManager().beginTransaction() .replace(android.R.id.content, mApnEditorFragment) .commit(); } @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case android.R.id.home: NavUtils.navigateUpFromSameTask(this); return true; } return super.onOptionsItemSelected(item); } @Override protected Dialog onCreateDialog(int id, Bundle args) { if (id == ERROR_DIALOG_ID) { String msg = args.getString(ERROR_MESSAGE_KEY); return new AlertDialog.Builder(this) .setPositiveButton(android.R.string.ok, null) .setMessage(msg) .create(); } return super.onCreateDialog(id); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: { if (mApnEditorFragment.validateAndSave(false)) { finish(); } return true; } } return super.onKeyDown(keyCode, event); } @Override protected void onPrepareDialog(int id, Dialog dialog, Bundle args) { super.onPrepareDialog(id, dialog); if (id == ERROR_DIALOG_ID) { final String msg = args.getString(ERROR_MESSAGE_KEY); if (msg != null) { ((AlertDialog) dialog).setMessage(msg); } } } public static class ApnEditorFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String SAVED_POS = "pos"; 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 EditTextPreference mMmsProxy; private EditTextPreference mMmsPort; private EditTextPreference mName; private EditTextPreference mMmsc; private EditTextPreference mMcc; private EditTextPreference mMnc; private static String sNotSet; private String mCurMnc; private String mCurMcc; private Cursor mCursor; private boolean mNewApn; private boolean mFirstTime; private String mCurrentId; private int mSubId; /** * 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.MMSC, // 2 Telephony.Carriers.MCC, // 3 Telephony.Carriers.MNC, // 4 Telephony.Carriers.NUMERIC, // 5 Telephony.Carriers.MMSPROXY, // 6 Telephony.Carriers.MMSPORT, // 7 Telephony.Carriers.TYPE, // 8 }; private static final int ID_INDEX = 0; private static final int NAME_INDEX = 1; private static final int MMSC_INDEX = 2; private static final int MCC_INDEX = 3; private static final int MNC_INDEX = 4; private static final int NUMERIC_INDEX = 5; private static final int MMSPROXY_INDEX = 6; private static final int MMSPORT_INDEX = 7; private static final int TYPE_INDEX = 8; private SQLiteDatabase mDatabase; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); addPreferencesFromResource(R.xml.apn_editor); setHasOptionsMenu(true); sNotSet = getResources().getString(R.string.apn_not_set); mName = (EditTextPreference) findPreference("apn_name"); 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"); final Intent intent = getActivity().getIntent(); mFirstTime = savedInstanceState == null; mCurrentId = intent.getStringExtra(UIIntents.UI_INTENT_EXTRA_APN_ROW_ID); mNewApn = mCurrentId == null; mDatabase = ApnDatabase.getApnDatabase().getWritableDatabase(); if (mNewApn) { fillUi(); } else { // Do initial query not on the UI thread new AsyncTask() { @Override protected Void doInBackground(Void... params) { if (mCurrentId != null) { String selection = Telephony.Carriers._ID + " =?"; String[] selectionArgs = new String[]{ mCurrentId }; mCursor = mDatabase.query(ApnDatabase.APN_TABLE, sProjection, selection, selectionArgs, null, null, null, null); } return null; } @Override protected void onPostExecute(Void result) { if (mCursor == null) { getActivity().finish(); return; } mCursor.moveToFirst(); fillUi(); } }.execute((Void) null); } } @Override public void onDestroy() { super.onDestroy(); if (mCursor != null) { mCursor.close(); mCursor = null; } } @Override public void onResume() { super.onResume(); getPreferenceScreen().getSharedPreferences() .registerOnSharedPreferenceChangeListener(this); } @Override public void onPause() { getPreferenceScreen().getSharedPreferences() .unregisterOnSharedPreferenceChangeListener(this); super.onPause(); } public void setSubId(final int subId) { mSubId = subId; } private void fillUi() { if (mNewApn) { mMcc.setText(null); mMnc.setText(null); String numeric = PhoneUtils.get(mSubId).getSimOperatorNumeric(); // 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; } mName.setText(null); mMmsProxy.setText(null); mMmsPort.setText(null); mMmsc.setText(null); } else if (mFirstTime) { mFirstTime = false; // Fill in all the values from the db in both text editor and summary mName.setText(mCursor.getString(NAME_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)); } mName.setSummary(checkNull(mName.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())); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); // 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_apn) .setIcon(R.drawable.ic_delete_small_dark); } menu.add(0, MENU_SAVE, 0, R.string.menu_save_apn) .setIcon(android.R.drawable.ic_menu_save); menu.add(0, MENU_CANCEL, 0, R.string.menu_discard_apn_change) .setIcon(android.R.drawable.ic_menu_close_clear_cancel); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_DELETE: deleteApn(); return true; case MENU_SAVE: if (validateAndSave(false)) { getActivity().finish(); } return true; case MENU_CANCEL: getActivity().finish(); return true; case android.R.id.home: getActivity().onBackPressed(); return true; } return super.onOptionsItemSelected(item); } @Override public void onSaveInstanceState(Bundle icicle) { super.onSaveInstanceState(icicle); if (validateAndSave(true) && mCursor != null) { 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) { final String name = checkNotSet(mName.getText()); final String mcc = checkNotSet(mMcc.getText()); final String mnc = checkNotSet(mMnc.getText()); if (getErrorMsg() != null && !force) { final Bundle bundle = new Bundle(); bundle.putString(ERROR_MESSAGE_KEY, getErrorMsg()); getActivity().showDialog(ERROR_DIALOG_ID, bundle); return false; } // Make database changes not on the UI thread new AsyncTask() { @Override protected Void doInBackground(Void... params) { 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.MMSPROXY, checkNotSet(mMmsProxy.getText())); values.put(Telephony.Carriers.MMSPORT, checkNotSet(mMmsPort.getText())); values.put(Telephony.Carriers.MMSC, checkNotSet(mMmsc.getText())); values.put(Telephony.Carriers.TYPE, BugleApnSettingsLoader.APN_TYPE_MMS); values.put(Telephony.Carriers.MCC, mcc); values.put(Telephony.Carriers.MNC, mnc); values.put(Telephony.Carriers.NUMERIC, mcc + mnc); if (mCurMnc != null && mCurMcc != null) { if (mCurMnc.equals(mnc) && mCurMcc.equals(mcc)) { values.put(Telephony.Carriers.CURRENT, 1); } } if (mNewApn) { mDatabase.insert(ApnDatabase.APN_TABLE, null, values); } else { // update the APN String selection = Telephony.Carriers._ID + " =?"; String[] selectionArgs = new String[]{ mCurrentId }; int updated = mDatabase.update(ApnDatabase.APN_TABLE, values, selection, selectionArgs); } return null; } }.execute((Void) null); return true; } private void deleteApn() { // Make database changes not on the UI thread new AsyncTask() { @Override protected Void doInBackground(Void... params) { // delete the APN String where = Telephony.Carriers._ID + " =?"; String[] whereArgs = new String[]{ mCurrentId }; mDatabase.delete(ApnDatabase.APN_TABLE, where, whereArgs); return null; } }.execute((Void) null); getActivity().finish(); } private String checkNull(String value) { if (value == null || value.length() == 0) { return sNotSet; } else { return value; } } public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { Preference pref = findPreference(key); if (pref != null) { pref.setSummary(checkNull(sharedPreferences.getString(key, ""))); } } private String getErrorMsg() { String errorMsg = null; String name = checkNotSet(mName.getText()); String mcc = checkNotSet(mMcc.getText()); String mnc = checkNotSet(mMnc.getText()); if (name.length() < 1) { errorMsg = getString(R.string.error_apn_name_empty); } else if (mcc.length() != 3) { errorMsg = getString(R.string.error_mcc_not3); } else if ((mnc.length() & 0xFFFE) != 2) { errorMsg = getString(R.string.error_mnc_not23); } return errorMsg; } private String checkNotSet(String value) { if (value == null || value.equals(sNotSet)) { return ""; } else { return value; } } } }