OSDN Git Service

0459a1346009500886749619e478016120cb250c
[android-x86/packages-apps-Settings.git] / src / com / android / settings / ApnSettings.java
1 /*
2  * Copyright (C) 2008 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 android.app.Activity;
20 import android.app.Dialog;
21 import android.app.ProgressDialog;
22 import android.content.BroadcastReceiver;
23 import android.content.ContentResolver;
24 import android.content.ContentUris;
25 import android.content.ContentValues;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.database.Cursor;
30 import android.net.Uri;
31 import android.os.Bundle;
32 import android.os.Handler;
33 import android.os.HandlerThread;
34 import android.os.Looper;
35 import android.os.Message;
36 import android.os.PersistableBundle;
37 import android.os.UserHandle;
38 import android.os.UserManager;
39 import android.preference.Preference;
40 import android.preference.PreferenceGroup;
41 import android.preference.PreferenceScreen;
42 import android.provider.Telephony;
43 import android.telephony.CarrierConfigManager;
44 import android.telephony.SubscriptionInfo;
45 import android.telephony.SubscriptionManager;
46 import android.text.TextUtils;
47 import android.util.Log;
48 import android.view.Menu;
49 import android.view.MenuInflater;
50 import android.view.MenuItem;
51 import android.widget.TextView;
52 import android.widget.Toast;
53
54 import com.android.internal.logging.MetricsLogger;
55 import com.android.internal.telephony.PhoneConstants;
56 import com.android.internal.telephony.TelephonyIntents;
57 import com.android.internal.telephony.dataconnection.ApnSetting;
58 import com.android.internal.telephony.uicc.IccRecords;
59 import com.android.internal.telephony.uicc.UiccController;
60
61 import android.telephony.TelephonyManager;
62
63 import java.util.ArrayList;
64
65 public class ApnSettings extends SettingsPreferenceFragment implements
66         Preference.OnPreferenceChangeListener {
67     static final String TAG = "ApnSettings";
68
69     public static final String EXTRA_POSITION = "position";
70     public static final String RESTORE_CARRIERS_URI =
71         "content://telephony/carriers/restore";
72     public static final String PREFERRED_APN_URI =
73         "content://telephony/carriers/preferapn";
74
75     public static final Uri PREFERRED_MSIM_APN_URI =
76             Uri.parse("content://telephony/carriers/preferapn/subIdImsi");
77
78     public static final String APN_ID = "apn_id";
79     public static final String SUB_ID = "sub_id";
80     public static final String EXTRA_IMSI = "imsi";
81     public static final String MVNO_TYPE = "mvno_type";
82     public static final String MVNO_MATCH_DATA = "mvno_match_data";
83
84     private static final int ID_INDEX = 0;
85     private static final int NAME_INDEX = 1;
86     private static final int APN_INDEX = 2;
87     private static final int TYPES_INDEX = 3;
88     private static final int MVNO_TYPE_INDEX = 4;
89     private static final int MVNO_MATCH_DATA_INDEX = 5;
90     private static final int RO_INDEX = 6;
91
92     private static final int MENU_NEW = Menu.FIRST;
93     private static final int MENU_RESTORE = Menu.FIRST + 1;
94
95     private static final int EVENT_RESTORE_DEFAULTAPN_START = 1;
96     private static final int EVENT_RESTORE_DEFAULTAPN_COMPLETE = 2;
97
98     private static final int DIALOG_RESTORE_DEFAULTAPN = 1001;
99
100     private static final Uri DEFAULTAPN_URI = Uri.parse(RESTORE_CARRIERS_URI);
101     private static final Uri PREFERAPN_URI = Uri.parse(PREFERRED_APN_URI);
102
103     private static boolean mRestoreDefaultApnMode;
104
105     private RestoreApnUiHandler mRestoreApnUiHandler;
106     private RestoreApnProcessHandler mRestoreApnProcessHandler;
107     private HandlerThread mRestoreDefaultApnThread;
108     private SubscriptionInfo mSubscriptionInfo;
109     private UiccController mUiccController;
110     private String mMvnoType;
111     private String mMvnoMatchData;
112
113     private UserManager mUm;
114
115     private String mSelectedKey;
116
117     private IntentFilter mMobileStateFilter;
118
119     private boolean mUnavailable;
120
121     private boolean mHideImsApn;
122     private boolean mAllowAddingApns;
123
124     private String mImsi;
125
126     private final BroadcastReceiver mMobileStateReceiver = new BroadcastReceiver() {
127         @Override
128         public void onReceive(Context context, Intent intent) {
129             if (intent.getAction().equals(
130                     TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
131                 PhoneConstants.DataState state = getMobileDataState(intent);
132                 switch (state) {
133                 case CONNECTED:
134                     if (!mRestoreDefaultApnMode) {
135                         fillList();
136                     } else {
137                         showDialog(DIALOG_RESTORE_DEFAULTAPN);
138                     }
139                     break;
140                 }
141             }
142         }
143     };
144
145     private static PhoneConstants.DataState getMobileDataState(Intent intent) {
146         String str = intent.getStringExtra(PhoneConstants.STATE_KEY);
147         if (str != null) {
148             return Enum.valueOf(PhoneConstants.DataState.class, str);
149         } else {
150             return PhoneConstants.DataState.DISCONNECTED;
151         }
152     }
153
154     @Override
155     protected int getMetricsCategory() {
156         return MetricsLogger.APN;
157     }
158
159     @Override
160     public void onCreate(Bundle icicle) {
161         super.onCreate(icicle);
162         final Activity activity = getActivity();
163         final int subId = activity.getIntent().getIntExtra(SUB_ID,
164                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
165
166         mImsi = activity.getIntent().getStringExtra(EXTRA_IMSI);
167         if (mImsi == null) {
168             mImsi = "";
169         }
170
171         mUm = (UserManager) getSystemService(Context.USER_SERVICE);
172
173         mMobileStateFilter = new IntentFilter(
174                 TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
175
176         if (!mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
177             setHasOptionsMenu(true);
178         }
179
180         mSubscriptionInfo = SubscriptionManager.from(activity).getActiveSubscriptionInfo(subId);
181         mUiccController = UiccController.getInstance();
182
183         CarrierConfigManager configManager = (CarrierConfigManager)
184                 getSystemService(Context.CARRIER_CONFIG_SERVICE);
185         PersistableBundle b = configManager.getConfig();
186         mHideImsApn = b.getBoolean(CarrierConfigManager.KEY_HIDE_IMS_APN_BOOL);
187         mAllowAddingApns = b.getBoolean(CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL);
188     }
189
190     @Override
191     public void onActivityCreated(Bundle savedInstanceState) {
192         super.onActivityCreated(savedInstanceState);
193
194         TextView empty = (TextView) getView().findViewById(android.R.id.empty);
195         if (empty != null) {
196             empty.setText(R.string.apn_settings_not_available);
197             getListView().setEmptyView(empty);
198         }
199
200         if (mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)
201                 || UserHandle.myUserId()!= UserHandle.USER_OWNER) {
202             mUnavailable = true;
203             setPreferenceScreen(new PreferenceScreen(getActivity(), null));
204             return;
205         }
206
207         addPreferencesFromResource(R.xml.apn_settings);
208
209         getListView().setItemsCanFocus(true);
210     }
211
212     @Override
213     public void onResume() {
214         super.onResume();
215
216         if (mUnavailable) {
217             return;
218         }
219
220         getActivity().registerReceiver(mMobileStateReceiver, mMobileStateFilter);
221
222         if (!mRestoreDefaultApnMode) {
223             fillList();
224         }
225     }
226
227     @Override
228     public void onPause() {
229         super.onPause();
230
231         if (mUnavailable) {
232             return;
233         }
234
235         getActivity().unregisterReceiver(mMobileStateReceiver);
236     }
237
238     @Override
239     public void onDestroy() {
240         super.onDestroy();
241
242         if (mRestoreDefaultApnThread != null) {
243             mRestoreDefaultApnThread.quit();
244         }
245     }
246
247     private void fillList() {
248         boolean isSelectedKeyMatch = false;
249         final TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
250         final String mccmnc = mSubscriptionInfo == null ? ""
251             : tm.getIccOperatorNumericForData(mSubscriptionInfo.getSubscriptionId());
252         Log.d(TAG, "mccmnc = " + mccmnc);
253         StringBuilder where = new StringBuilder("numeric=\"" + mccmnc +
254                 "\" AND NOT (type='ia' AND (apn=\"\" OR apn IS NULL)) AND user_visible!=0");
255
256         if (mHideImsApn) {
257             where.append(" AND NOT (type='ims')");
258         }
259
260         Cursor cursor = getContentResolver().query(Telephony.Carriers.CONTENT_URI, new String[] {
261                 "_id", "name", "apn", "type", "mvno_type", "mvno_match_data", "read_only"}, where.toString(),
262                 null, Telephony.Carriers.DEFAULT_SORT_ORDER);
263
264         if (cursor != null) {
265             IccRecords r = null;
266             if (mUiccController != null && mSubscriptionInfo != null) {
267                 r = mUiccController.getIccRecords(SubscriptionManager.getPhoneId(
268                         mSubscriptionInfo.getSubscriptionId()), UiccController.APP_FAM_3GPP);
269             }
270             PreferenceGroup apnList = (PreferenceGroup) findPreference("apn_list");
271             apnList.removeAll();
272
273             ArrayList<ApnPreference> mnoApnList = new ArrayList<ApnPreference>();
274             ArrayList<ApnPreference> mvnoApnList = new ArrayList<ApnPreference>();
275             ArrayList<ApnPreference> mnoMmsApnList = new ArrayList<ApnPreference>();
276             ArrayList<ApnPreference> mvnoMmsApnList = new ArrayList<ApnPreference>();
277
278             mSelectedKey = getSelectedApnKey();
279             cursor.moveToFirst();
280             while (!cursor.isAfterLast()) {
281                 String name = cursor.getString(NAME_INDEX);
282                 String apn = cursor.getString(APN_INDEX);
283                 String key = cursor.getString(ID_INDEX);
284                 String type = cursor.getString(TYPES_INDEX);
285                 String mvnoType = cursor.getString(MVNO_TYPE_INDEX);
286                 String mvnoMatchData = cursor.getString(MVNO_MATCH_DATA_INDEX);
287                 boolean readOnly = (cursor.getInt(RO_INDEX) == 1);
288
289                 ApnPreference pref = new ApnPreference(getActivity());
290
291                 pref.setApnReadOnly(readOnly);
292                 pref.setKey(key);
293                 pref.setTitle(name);
294                 pref.setSummary(apn);
295                 pref.setPersistent(false);
296                 pref.setOnPreferenceChangeListener(this);
297
298                 boolean selectable = ((type == null) || !type.equals("mms"));
299                 pref.setSelectable(selectable);
300                 if (selectable) {
301                     if ((mSelectedKey != null) && mSelectedKey.equals(key)) {
302                         pref.setChecked();
303                         isSelectedKeyMatch = true;
304                         Log.d(TAG, "find select key = " + mSelectedKey);
305                     }
306                     addApnToList(pref, mnoApnList, mvnoApnList, r, mvnoType, mvnoMatchData);
307                 } else {
308                     addApnToList(pref, mnoMmsApnList, mvnoMmsApnList, r, mvnoType, mvnoMatchData);
309                 }
310                 cursor.moveToNext();
311             }
312             cursor.close();
313
314             if (!mvnoApnList.isEmpty()) {
315                 mnoApnList = mvnoApnList;
316                 mnoMmsApnList = mvnoMmsApnList;
317
318                 // Also save the mvno info
319             }
320
321             for (Preference preference : mnoApnList) {
322                 apnList.addPreference(preference);
323             }
324
325             //if find no selectedKey, set the first one as selected key
326             if (!isSelectedKeyMatch && apnList.getPreferenceCount() > 0) {
327                 ApnPreference pref = (ApnPreference) apnList.getPreference(0);
328                 pref.setChecked();
329                 setSelectedApnKey(pref.getKey());
330                 Log.d(TAG, "set key to  " +pref.getKey());
331             }
332
333             for (Preference preference : mnoMmsApnList) {
334                 apnList.addPreference(preference);
335             }
336         }
337     }
338
339     private void addApnToList(ApnPreference pref, ArrayList<ApnPreference> mnoList,
340                               ArrayList<ApnPreference> mvnoList, IccRecords r, String mvnoType,
341                               String mvnoMatchData) {
342         if (r != null && !TextUtils.isEmpty(mvnoType) && !TextUtils.isEmpty(mvnoMatchData)) {
343             if (ApnSetting.mvnoMatches(r, mvnoType, mvnoMatchData)) {
344                 mvnoList.add(pref);
345                 // Since adding to mvno list, save mvno info
346                 mMvnoType = mvnoType;
347                 mMvnoMatchData = mvnoMatchData;
348             }
349         } else {
350             mnoList.add(pref);
351         }
352     }
353
354     @Override
355     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
356         if (!mUnavailable) {
357             if (mAllowAddingApns) {
358                 menu.add(0, MENU_NEW, 0,
359                         getResources().getString(R.string.menu_new))
360                         .setIcon(R.drawable.ic_menu_add_white)
361                         .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
362             }
363             menu.add(0, MENU_RESTORE, 0,
364                     getResources().getString(R.string.menu_restore))
365                     .setIcon(android.R.drawable.ic_menu_upload);
366         }
367
368         super.onCreateOptionsMenu(menu, inflater);
369     }
370
371     @Override
372     public boolean onOptionsItemSelected(MenuItem item) {
373         switch (item.getItemId()) {
374         case MENU_NEW:
375             addNewApn();
376             return true;
377
378         case MENU_RESTORE:
379             restoreDefaultApn();
380             return true;
381         }
382         return super.onOptionsItemSelected(item);
383     }
384
385     private void addNewApn() {
386         Intent intent = new Intent(Intent.ACTION_INSERT, Telephony.Carriers.CONTENT_URI);
387         int subId = mSubscriptionInfo != null ? mSubscriptionInfo.getSubscriptionId()
388                 : SubscriptionManager.INVALID_SUBSCRIPTION_ID;
389         intent.putExtra(SUB_ID, subId);
390         if (!TextUtils.isEmpty(mMvnoType) && !TextUtils.isEmpty(mMvnoMatchData)) {
391             intent.putExtra(MVNO_TYPE, mMvnoType);
392             intent.putExtra(MVNO_MATCH_DATA, mMvnoMatchData);
393         }
394         startActivity(intent);
395     }
396
397     @Override
398     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
399         int pos = Integer.parseInt(preference.getKey());
400         Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
401         startActivity(new Intent(Intent.ACTION_EDIT, url));
402         return true;
403     }
404
405     public boolean onPreferenceChange(Preference preference, Object newValue) {
406         Log.d(TAG, "onPreferenceChange(): Preference - " + preference
407                 + ", newValue - " + newValue + ", newValue type - "
408                 + newValue.getClass());
409         if (newValue instanceof String) {
410             setSelectedApnKey((String) newValue);
411         }
412
413         return true;
414     }
415
416     private void setSelectedApnKey(String key) {
417         mSelectedKey = key;
418         ContentResolver resolver = getContentResolver();
419
420         ContentValues values = new ContentValues();
421         values.put(APN_ID, mSelectedKey);
422         if (TelephonyManager.getDefault().getPhoneCount() > 1) {
423             Uri qUri = Uri.withAppendedPath(PREFERRED_MSIM_APN_URI,
424                     String.valueOf(mSubscriptionInfo.getSubscriptionId()));
425             qUri = Uri.withAppendedPath(qUri, mImsi);
426             resolver.update(qUri, values, null, null);
427         } else {
428             resolver.update(PREFERAPN_URI, values, null, null);
429         }
430     }
431
432     private String getSelectedApnKey() {
433         String key = null;
434
435         Uri uri;
436         if (TelephonyManager.getDefault().getPhoneCount() > 1) {
437             uri = Uri.withAppendedPath(PREFERRED_MSIM_APN_URI,
438                     String.valueOf(mSubscriptionInfo.getSubscriptionId()));
439             uri = Uri.withAppendedPath(uri, mImsi);
440         } else {
441             uri = PREFERAPN_URI;
442         }
443         try (Cursor cursor = getContentResolver().query(uri, new String[] {"_id"},
444                 null, null, Telephony.Carriers.DEFAULT_SORT_ORDER)) {
445             if (cursor != null && cursor.getCount() > 0) {
446                 cursor.moveToFirst();
447                 key = cursor.getString(ID_INDEX);
448             }
449         }
450         return key;
451     }
452
453     private boolean restoreDefaultApn() {
454         showDialog(DIALOG_RESTORE_DEFAULTAPN);
455         mRestoreDefaultApnMode = true;
456
457         if (mRestoreApnUiHandler == null) {
458             mRestoreApnUiHandler = new RestoreApnUiHandler();
459         }
460
461         if (mRestoreApnProcessHandler == null ||
462             mRestoreDefaultApnThread == null) {
463             mRestoreDefaultApnThread = new HandlerThread(
464                     "Restore default APN Handler: Process Thread");
465             mRestoreDefaultApnThread.start();
466             mRestoreApnProcessHandler = new RestoreApnProcessHandler(
467                     mRestoreDefaultApnThread.getLooper(), mRestoreApnUiHandler);
468         }
469
470         mRestoreApnProcessHandler
471                 .sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_START);
472         return true;
473     }
474
475     private class RestoreApnUiHandler extends Handler {
476         @Override
477         public void handleMessage(Message msg) {
478             switch (msg.what) {
479                 case EVENT_RESTORE_DEFAULTAPN_COMPLETE:
480                     Activity activity = getActivity();
481                     if (activity == null) {
482                         mRestoreDefaultApnMode = false;
483                         return;
484                     }
485                     fillList();
486                     getPreferenceScreen().setEnabled(true);
487                     mRestoreDefaultApnMode = false;
488                     removeDialog(DIALOG_RESTORE_DEFAULTAPN);
489                     Toast.makeText(
490                         activity,
491                         getResources().getString(
492                                 R.string.restore_default_apn_completed),
493                         Toast.LENGTH_LONG).show();
494                     break;
495             }
496         }
497     }
498
499     private class RestoreApnProcessHandler extends Handler {
500         private Handler mRestoreApnUiHandler;
501
502         public RestoreApnProcessHandler(Looper looper, Handler restoreApnUiHandler) {
503             super(looper);
504             this.mRestoreApnUiHandler = restoreApnUiHandler;
505         }
506
507         @Override
508         public void handleMessage(Message msg) {
509             switch (msg.what) {
510                 case EVENT_RESTORE_DEFAULTAPN_START:
511                     ContentResolver resolver = getContentResolver();
512                     resolver.delete(DEFAULTAPN_URI, null, null);
513                     mRestoreApnUiHandler
514                         .sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_COMPLETE);
515                     break;
516             }
517         }
518     }
519
520     @Override
521     public Dialog onCreateDialog(int id) {
522         if (id == DIALOG_RESTORE_DEFAULTAPN) {
523             ProgressDialog dialog = new ProgressDialog(getActivity());
524             dialog.setMessage(getResources().getString(R.string.restore_default_apn));
525             dialog.setCancelable(false);
526             return dialog;
527         }
528         return null;
529     }
530 }