Home | History | Annotate | Download | only in appsettings
      1 /*
      2  * Copyright (C) 2015 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.messaging.ui.appsettings;
     18 
     19 import android.app.AlertDialog;
     20 import android.app.Dialog;
     21 import android.content.ContentValues;
     22 import android.content.Intent;
     23 import android.content.SharedPreferences;
     24 import android.database.Cursor;
     25 import android.database.sqlite.SQLiteDatabase;
     26 import android.os.AsyncTask;
     27 import android.os.Bundle;
     28 import android.preference.EditTextPreference;
     29 import android.preference.Preference;
     30 import android.preference.PreferenceFragment;
     31 import android.provider.Telephony;
     32 import android.support.v4.app.NavUtils;
     33 import android.view.KeyEvent;
     34 import android.view.Menu;
     35 import android.view.MenuInflater;
     36 import android.view.MenuItem;
     37 
     38 import com.android.messaging.R;
     39 import com.android.messaging.datamodel.data.ParticipantData;
     40 import com.android.messaging.sms.ApnDatabase;
     41 import com.android.messaging.sms.BugleApnSettingsLoader;
     42 import com.android.messaging.ui.BugleActionBarActivity;
     43 import com.android.messaging.ui.UIIntents;
     44 import com.android.messaging.util.PhoneUtils;
     45 
     46 public class ApnEditorActivity extends BugleActionBarActivity {
     47     private static final int ERROR_DIALOG_ID = 0;
     48     private static final String ERROR_MESSAGE_KEY = "error_msg";
     49     private ApnEditorFragment mApnEditorFragment;
     50 
     51     @Override
     52     protected void onCreate(Bundle savedInstanceState) {
     53         super.onCreate(savedInstanceState);
     54 
     55         getSupportActionBar().setDisplayHomeAsUpEnabled(true);
     56 
     57         // Display the fragment as the main content.
     58         mApnEditorFragment = new ApnEditorFragment();
     59         mApnEditorFragment.setSubId(getIntent().getIntExtra(UIIntents.UI_INTENT_EXTRA_SUB_ID,
     60                 ParticipantData.DEFAULT_SELF_SUB_ID));
     61         getFragmentManager().beginTransaction()
     62             .replace(android.R.id.content, mApnEditorFragment)
     63             .commit();
     64     }
     65 
     66     @Override
     67     public boolean onOptionsItemSelected(final MenuItem item) {
     68         switch (item.getItemId()) {
     69             case android.R.id.home:
     70                 NavUtils.navigateUpFromSameTask(this);
     71                 return true;
     72         }
     73         return super.onOptionsItemSelected(item);
     74     }
     75 
     76     @Override
     77     protected Dialog onCreateDialog(int id, Bundle args) {
     78 
     79         if (id == ERROR_DIALOG_ID) {
     80             String msg = args.getString(ERROR_MESSAGE_KEY);
     81 
     82             return new AlertDialog.Builder(this)
     83                 .setPositiveButton(android.R.string.ok, null)
     84                 .setMessage(msg)
     85                 .create();
     86         }
     87 
     88         return super.onCreateDialog(id);
     89     }
     90 
     91     @Override
     92     public boolean onKeyDown(int keyCode, KeyEvent event) {
     93         switch (keyCode) {
     94             case KeyEvent.KEYCODE_BACK: {
     95                 if (mApnEditorFragment.validateAndSave(false)) {
     96                     finish();
     97                 }
     98                 return true;
     99             }
    100         }
    101         return super.onKeyDown(keyCode, event);
    102     }
    103 
    104     @Override
    105     protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
    106         super.onPrepareDialog(id, dialog);
    107 
    108         if (id == ERROR_DIALOG_ID) {
    109             final String msg = args.getString(ERROR_MESSAGE_KEY);
    110 
    111             if (msg != null) {
    112                 ((AlertDialog) dialog).setMessage(msg);
    113             }
    114         }
    115     }
    116 
    117     public static class ApnEditorFragment extends PreferenceFragment implements
    118         SharedPreferences.OnSharedPreferenceChangeListener {
    119 
    120         private static final String SAVED_POS = "pos";
    121 
    122         private static final int MENU_DELETE = Menu.FIRST;
    123         private static final int MENU_SAVE = Menu.FIRST + 1;
    124         private static final int MENU_CANCEL = Menu.FIRST + 2;
    125 
    126         private EditTextPreference mMmsProxy;
    127         private EditTextPreference mMmsPort;
    128         private EditTextPreference mName;
    129         private EditTextPreference mMmsc;
    130         private EditTextPreference mMcc;
    131         private EditTextPreference mMnc;
    132         private static String sNotSet;
    133 
    134         private String mCurMnc;
    135         private String mCurMcc;
    136 
    137         private Cursor mCursor;
    138         private boolean mNewApn;
    139         private boolean mFirstTime;
    140         private String mCurrentId;
    141 
    142         private int mSubId;
    143 
    144         /**
    145          * Standard projection for the interesting columns of a normal note.
    146          */
    147         private static final String[] sProjection = new String[] {
    148             Telephony.Carriers._ID,         // 0
    149             Telephony.Carriers.NAME,        // 1
    150             Telephony.Carriers.MMSC,        // 2
    151             Telephony.Carriers.MCC,         // 3
    152             Telephony.Carriers.MNC,         // 4
    153             Telephony.Carriers.NUMERIC,     // 5
    154             Telephony.Carriers.MMSPROXY,    // 6
    155             Telephony.Carriers.MMSPORT,     // 7
    156             Telephony.Carriers.TYPE,        // 8
    157         };
    158 
    159         private static final int ID_INDEX = 0;
    160         private static final int NAME_INDEX = 1;
    161         private static final int MMSC_INDEX = 2;
    162         private static final int MCC_INDEX = 3;
    163         private static final int MNC_INDEX = 4;
    164         private static final int NUMERIC_INDEX = 5;
    165         private static final int MMSPROXY_INDEX = 6;
    166         private static final int MMSPORT_INDEX = 7;
    167         private static final int TYPE_INDEX = 8;
    168 
    169         private SQLiteDatabase mDatabase;
    170 
    171         @Override
    172         public void onCreate(Bundle icicle) {
    173             super.onCreate(icicle);
    174 
    175         }
    176 
    177         @Override
    178         public void onActivityCreated(Bundle savedInstanceState) {
    179             super.onActivityCreated(savedInstanceState);
    180 
    181             addPreferencesFromResource(R.xml.apn_editor);
    182 
    183             setHasOptionsMenu(true);
    184 
    185             sNotSet = getResources().getString(R.string.apn_not_set);
    186             mName = (EditTextPreference) findPreference("apn_name");
    187             mMmsProxy = (EditTextPreference) findPreference("apn_mms_proxy");
    188             mMmsPort = (EditTextPreference) findPreference("apn_mms_port");
    189             mMmsc = (EditTextPreference) findPreference("apn_mmsc");
    190             mMcc = (EditTextPreference) findPreference("apn_mcc");
    191             mMnc = (EditTextPreference) findPreference("apn_mnc");
    192 
    193             final Intent intent = getActivity().getIntent();
    194 
    195             mFirstTime = savedInstanceState == null;
    196             mCurrentId = intent.getStringExtra(UIIntents.UI_INTENT_EXTRA_APN_ROW_ID);
    197             mNewApn = mCurrentId == null;
    198 
    199             mDatabase = ApnDatabase.getApnDatabase().getWritableDatabase();
    200 
    201             if (mNewApn) {
    202                 fillUi();
    203             } else {
    204                 // Do initial query not on the UI thread
    205                 new AsyncTask<Void, Void, Void>() {
    206                     @Override
    207                     protected Void doInBackground(Void... params) {
    208                         if (mCurrentId != null) {
    209                             String selection = Telephony.Carriers._ID + " =?";
    210                             String[] selectionArgs = new String[]{ mCurrentId };
    211                             mCursor = mDatabase.query(ApnDatabase.APN_TABLE, sProjection, selection,
    212                                     selectionArgs, null, null, null, null);
    213                         }
    214                         return null;
    215                     }
    216 
    217                     @Override
    218                     protected void onPostExecute(Void result) {
    219                         if (mCursor == null) {
    220                             getActivity().finish();
    221                             return;
    222                         }
    223                         mCursor.moveToFirst();
    224 
    225                         fillUi();
    226                     }
    227                 }.execute((Void) null);
    228             }
    229         }
    230 
    231         @Override
    232         public void onDestroy() {
    233             super.onDestroy();
    234             if (mCursor != null) {
    235                 mCursor.close();
    236                 mCursor = null;
    237             }
    238         }
    239 
    240         @Override
    241         public void onResume() {
    242             super.onResume();
    243             getPreferenceScreen().getSharedPreferences()
    244             .registerOnSharedPreferenceChangeListener(this);
    245         }
    246 
    247         @Override
    248         public void onPause() {
    249             getPreferenceScreen().getSharedPreferences()
    250             .unregisterOnSharedPreferenceChangeListener(this);
    251             super.onPause();
    252         }
    253 
    254         public void setSubId(final int subId) {
    255             mSubId = subId;
    256         }
    257 
    258         private void fillUi() {
    259             if (mNewApn) {
    260                 mMcc.setText(null);
    261                 mMnc.setText(null);
    262                 String numeric = PhoneUtils.get(mSubId).getSimOperatorNumeric();
    263                 // MCC is first 3 chars and then in 2 - 3 chars of MNC
    264                 if (numeric != null && numeric.length() > 4) {
    265                     // Country code
    266                     String mcc = numeric.substring(0, 3);
    267                     // Network code
    268                     String mnc = numeric.substring(3);
    269                     // Auto populate MNC and MCC for new entries, based on what SIM reports
    270                     mMcc.setText(mcc);
    271                     mMnc.setText(mnc);
    272                     mCurMnc = mnc;
    273                     mCurMcc = mcc;
    274                 }
    275                 mName.setText(null);
    276                 mMmsProxy.setText(null);
    277                 mMmsPort.setText(null);
    278                 mMmsc.setText(null);
    279             } else if (mFirstTime) {
    280                 mFirstTime = false;
    281                 // Fill in all the values from the db in both text editor and summary
    282                 mName.setText(mCursor.getString(NAME_INDEX));
    283                 mMmsProxy.setText(mCursor.getString(MMSPROXY_INDEX));
    284                 mMmsPort.setText(mCursor.getString(MMSPORT_INDEX));
    285                 mMmsc.setText(mCursor.getString(MMSC_INDEX));
    286                 mMcc.setText(mCursor.getString(MCC_INDEX));
    287                 mMnc.setText(mCursor.getString(MNC_INDEX));
    288             }
    289 
    290             mName.setSummary(checkNull(mName.getText()));
    291             mMmsProxy.setSummary(checkNull(mMmsProxy.getText()));
    292             mMmsPort.setSummary(checkNull(mMmsPort.getText()));
    293             mMmsc.setSummary(checkNull(mMmsc.getText()));
    294             mMcc.setSummary(checkNull(mMcc.getText()));
    295             mMnc.setSummary(checkNull(mMnc.getText()));
    296         }
    297 
    298         @Override
    299         public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    300             super.onCreateOptionsMenu(menu, inflater);
    301             // If it's a new APN, then cancel will delete the new entry in onPause
    302             if (!mNewApn) {
    303                 menu.add(0, MENU_DELETE, 0, R.string.menu_delete_apn)
    304                     .setIcon(R.drawable.ic_delete_small_dark);
    305             }
    306             menu.add(0, MENU_SAVE, 0, R.string.menu_save_apn)
    307                 .setIcon(android.R.drawable.ic_menu_save);
    308             menu.add(0, MENU_CANCEL, 0, R.string.menu_discard_apn_change)
    309                 .setIcon(android.R.drawable.ic_menu_close_clear_cancel);
    310         }
    311 
    312         @Override
    313         public boolean onOptionsItemSelected(MenuItem item) {
    314             switch (item.getItemId()) {
    315                 case MENU_DELETE:
    316                     deleteApn();
    317                     return true;
    318 
    319                 case MENU_SAVE:
    320                     if (validateAndSave(false)) {
    321                         getActivity().finish();
    322                     }
    323                     return true;
    324 
    325                 case MENU_CANCEL:
    326                     getActivity().finish();
    327                     return true;
    328 
    329                 case android.R.id.home:
    330                     getActivity().onBackPressed();
    331                     return true;
    332             }
    333             return super.onOptionsItemSelected(item);
    334         }
    335 
    336         @Override
    337         public void onSaveInstanceState(Bundle icicle) {
    338             super.onSaveInstanceState(icicle);
    339             if (validateAndSave(true) && mCursor != null) {
    340                 icicle.putInt(SAVED_POS, mCursor.getInt(ID_INDEX));
    341             }
    342         }
    343 
    344         /**
    345          * Check the key fields' validity and save if valid.
    346          * @param force save even if the fields are not valid, if the app is
    347          *        being suspended
    348          * @return true if the data was saved
    349          */
    350         private boolean validateAndSave(boolean force) {
    351             final String name = checkNotSet(mName.getText());
    352             final String mcc = checkNotSet(mMcc.getText());
    353             final String mnc = checkNotSet(mMnc.getText());
    354 
    355             if (getErrorMsg() != null && !force) {
    356                 final Bundle bundle = new Bundle();
    357                 bundle.putString(ERROR_MESSAGE_KEY, getErrorMsg());
    358                 getActivity().showDialog(ERROR_DIALOG_ID, bundle);
    359                 return false;
    360             }
    361 
    362             // Make database changes not on the UI thread
    363             new AsyncTask<Void, Void, Void>() {
    364                 @Override
    365                 protected Void doInBackground(Void... params) {
    366                     ContentValues values = new ContentValues();
    367 
    368                     // Add a dummy name "Untitled", if the user exits the screen without adding a
    369                     // name but entered other information worth keeping.
    370                     values.put(Telephony.Carriers.NAME, name.length() < 1 ?
    371                             getResources().getString(R.string.untitled_apn) : name);
    372                     values.put(Telephony.Carriers.MMSPROXY, checkNotSet(mMmsProxy.getText()));
    373                     values.put(Telephony.Carriers.MMSPORT, checkNotSet(mMmsPort.getText()));
    374                     values.put(Telephony.Carriers.MMSC, checkNotSet(mMmsc.getText()));
    375 
    376                     values.put(Telephony.Carriers.TYPE, BugleApnSettingsLoader.APN_TYPE_MMS);
    377 
    378                     values.put(Telephony.Carriers.MCC, mcc);
    379                     values.put(Telephony.Carriers.MNC, mnc);
    380 
    381                     values.put(Telephony.Carriers.NUMERIC, mcc + mnc);
    382 
    383                     if (mCurMnc != null && mCurMcc != null) {
    384                         if (mCurMnc.equals(mnc) && mCurMcc.equals(mcc)) {
    385                             values.put(Telephony.Carriers.CURRENT, 1);
    386                         }
    387                     }
    388 
    389                     if (mNewApn) {
    390                         mDatabase.insert(ApnDatabase.APN_TABLE, null, values);
    391                     } else {
    392                         // update the APN
    393                         String selection = Telephony.Carriers._ID + " =?";
    394                         String[] selectionArgs = new String[]{ mCurrentId };
    395                         int updated = mDatabase.update(ApnDatabase.APN_TABLE, values,
    396                                 selection, selectionArgs);
    397                     }
    398                     return null;
    399                 }
    400             }.execute((Void) null);
    401 
    402             return true;
    403         }
    404 
    405         private void deleteApn() {
    406             // Make database changes not on the UI thread
    407             new AsyncTask<Void, Void, Void>() {
    408                 @Override
    409                 protected Void doInBackground(Void... params) {
    410                     // delete the APN
    411                     String where = Telephony.Carriers._ID + " =?";
    412                     String[] whereArgs = new String[]{ mCurrentId };
    413 
    414                     mDatabase.delete(ApnDatabase.APN_TABLE, where, whereArgs);
    415                     return null;
    416                 }
    417             }.execute((Void) null);
    418 
    419             getActivity().finish();
    420         }
    421 
    422         private String checkNull(String value) {
    423             if (value == null || value.length() == 0) {
    424                 return sNotSet;
    425             } else {
    426                 return value;
    427             }
    428         }
    429 
    430         public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
    431             Preference pref = findPreference(key);
    432             if (pref != null) {
    433                 pref.setSummary(checkNull(sharedPreferences.getString(key, "")));
    434             }
    435         }
    436 
    437         private String getErrorMsg() {
    438             String errorMsg = null;
    439 
    440             String name = checkNotSet(mName.getText());
    441             String mcc = checkNotSet(mMcc.getText());
    442             String mnc = checkNotSet(mMnc.getText());
    443 
    444             if (name.length() < 1) {
    445                 errorMsg = getString(R.string.error_apn_name_empty);
    446             } else if (mcc.length() != 3) {
    447                 errorMsg = getString(R.string.error_mcc_not3);
    448             } else if ((mnc.length() & 0xFFFE) != 2) {
    449                 errorMsg = getString(R.string.error_mnc_not23);
    450             }
    451 
    452             return errorMsg;
    453         }
    454 
    455         private String checkNotSet(String value) {
    456             if (value == null || value.equals(sNotSet)) {
    457                 return "";
    458             } else {
    459                 return value;
    460             }
    461         }
    462     }
    463 }
    464