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