2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings;
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;
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;
61 import android.telephony.TelephonyManager;
63 import java.util.ArrayList;
65 public class ApnSettings extends SettingsPreferenceFragment implements
66 Preference.OnPreferenceChangeListener {
67 static final String TAG = "ApnSettings";
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";
75 public static final Uri PREFERRED_MSIM_APN_URI =
76 Uri.parse("content://telephony/carriers/preferapn/subIdImsi");
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";
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;
92 private static final int MENU_NEW = Menu.FIRST;
93 private static final int MENU_RESTORE = Menu.FIRST + 1;
95 private static final int EVENT_RESTORE_DEFAULTAPN_START = 1;
96 private static final int EVENT_RESTORE_DEFAULTAPN_COMPLETE = 2;
98 private static final int DIALOG_RESTORE_DEFAULTAPN = 1001;
100 private static final Uri DEFAULTAPN_URI = Uri.parse(RESTORE_CARRIERS_URI);
101 private static final Uri PREFERAPN_URI = Uri.parse(PREFERRED_APN_URI);
103 private static boolean mRestoreDefaultApnMode;
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;
113 private UserManager mUm;
115 private String mSelectedKey;
117 private IntentFilter mMobileStateFilter;
119 private boolean mUnavailable;
121 private boolean mHideImsApn;
122 private boolean mAllowAddingApns;
124 private String mImsi;
126 private final BroadcastReceiver mMobileStateReceiver = new BroadcastReceiver() {
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);
134 if (!mRestoreDefaultApnMode) {
137 showDialog(DIALOG_RESTORE_DEFAULTAPN);
145 private static PhoneConstants.DataState getMobileDataState(Intent intent) {
146 String str = intent.getStringExtra(PhoneConstants.STATE_KEY);
148 return Enum.valueOf(PhoneConstants.DataState.class, str);
150 return PhoneConstants.DataState.DISCONNECTED;
155 protected int getMetricsCategory() {
156 return MetricsLogger.APN;
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);
166 mImsi = activity.getIntent().getStringExtra(EXTRA_IMSI);
168 mUm = (UserManager) getSystemService(Context.USER_SERVICE);
170 mMobileStateFilter = new IntentFilter(
171 TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
173 if (!mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
174 setHasOptionsMenu(true);
177 mSubscriptionInfo = SubscriptionManager.from(activity).getActiveSubscriptionInfo(subId);
178 mUiccController = UiccController.getInstance();
180 CarrierConfigManager configManager = (CarrierConfigManager)
181 getSystemService(Context.CARRIER_CONFIG_SERVICE);
182 PersistableBundle b = configManager.getConfig();
183 mHideImsApn = b.getBoolean(CarrierConfigManager.KEY_HIDE_IMS_APN_BOOL);
184 mAllowAddingApns = b.getBoolean(CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL);
188 public void onActivityCreated(Bundle savedInstanceState) {
189 super.onActivityCreated(savedInstanceState);
191 TextView empty = (TextView) getView().findViewById(android.R.id.empty);
193 empty.setText(R.string.apn_settings_not_available);
194 getListView().setEmptyView(empty);
197 if (mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)
198 || UserHandle.myUserId()!= UserHandle.USER_OWNER) {
200 setPreferenceScreen(new PreferenceScreen(getActivity(), null));
204 addPreferencesFromResource(R.xml.apn_settings);
206 getListView().setItemsCanFocus(true);
210 public void onResume() {
217 getActivity().registerReceiver(mMobileStateReceiver, mMobileStateFilter);
219 if (!mRestoreDefaultApnMode) {
225 public void onPause() {
232 getActivity().unregisterReceiver(mMobileStateReceiver);
236 public void onDestroy() {
239 if (mRestoreDefaultApnThread != null) {
240 mRestoreDefaultApnThread.quit();
244 private void fillList() {
245 boolean isSelectedKeyMatch = false;
246 final TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
247 final String mccmnc = mSubscriptionInfo == null ? ""
248 : tm.getIccOperatorNumericForData(mSubscriptionInfo.getSubscriptionId());
249 Log.d(TAG, "mccmnc = " + mccmnc);
250 StringBuilder where = new StringBuilder("numeric=\"" + mccmnc +
251 "\" AND NOT (type='ia' AND (apn=\"\" OR apn IS NULL)) AND user_visible!=0");
254 where.append(" AND NOT (type='ims')");
257 Cursor cursor = getContentResolver().query(Telephony.Carriers.CONTENT_URI, new String[] {
258 "_id", "name", "apn", "type", "mvno_type", "mvno_match_data", "read_only"}, where.toString(),
259 null, Telephony.Carriers.DEFAULT_SORT_ORDER);
261 if (cursor != null) {
263 if (mUiccController != null && mSubscriptionInfo != null) {
264 r = mUiccController.getIccRecords(SubscriptionManager.getPhoneId(
265 mSubscriptionInfo.getSubscriptionId()), UiccController.APP_FAM_3GPP);
267 PreferenceGroup apnList = (PreferenceGroup) findPreference("apn_list");
270 ArrayList<ApnPreference> mnoApnList = new ArrayList<ApnPreference>();
271 ArrayList<ApnPreference> mvnoApnList = new ArrayList<ApnPreference>();
272 ArrayList<ApnPreference> mnoMmsApnList = new ArrayList<ApnPreference>();
273 ArrayList<ApnPreference> mvnoMmsApnList = new ArrayList<ApnPreference>();
275 mSelectedKey = getSelectedApnKey();
276 cursor.moveToFirst();
277 while (!cursor.isAfterLast()) {
278 String name = cursor.getString(NAME_INDEX);
279 String apn = cursor.getString(APN_INDEX);
280 String key = cursor.getString(ID_INDEX);
281 String type = cursor.getString(TYPES_INDEX);
282 String mvnoType = cursor.getString(MVNO_TYPE_INDEX);
283 String mvnoMatchData = cursor.getString(MVNO_MATCH_DATA_INDEX);
284 boolean readOnly = (cursor.getInt(RO_INDEX) == 1);
286 ApnPreference pref = new ApnPreference(getActivity());
288 pref.setApnReadOnly(readOnly);
291 pref.setSummary(apn);
292 pref.setPersistent(false);
293 pref.setOnPreferenceChangeListener(this);
295 boolean selectable = ((type == null) || !type.equals("mms"));
296 pref.setSelectable(selectable);
298 if ((mSelectedKey != null) && mSelectedKey.equals(key)) {
300 isSelectedKeyMatch = true;
301 Log.d(TAG, "find select key = " + mSelectedKey);
303 addApnToList(pref, mnoApnList, mvnoApnList, r, mvnoType, mvnoMatchData);
305 addApnToList(pref, mnoMmsApnList, mvnoMmsApnList, r, mvnoType, mvnoMatchData);
311 if (!mvnoApnList.isEmpty()) {
312 mnoApnList = mvnoApnList;
313 mnoMmsApnList = mvnoMmsApnList;
315 // Also save the mvno info
318 for (Preference preference : mnoApnList) {
319 apnList.addPreference(preference);
322 //if find no selectedKey, set the first one as selected key
323 if (!isSelectedKeyMatch && apnList.getPreferenceCount() > 0) {
324 ApnPreference pref = (ApnPreference) apnList.getPreference(0);
326 setSelectedApnKey(pref.getKey());
327 Log.d(TAG, "set key to " +pref.getKey());
330 for (Preference preference : mnoMmsApnList) {
331 apnList.addPreference(preference);
336 private void addApnToList(ApnPreference pref, ArrayList<ApnPreference> mnoList,
337 ArrayList<ApnPreference> mvnoList, IccRecords r, String mvnoType,
338 String mvnoMatchData) {
339 if (r != null && !TextUtils.isEmpty(mvnoType) && !TextUtils.isEmpty(mvnoMatchData)) {
340 if (ApnSetting.mvnoMatches(r, mvnoType, mvnoMatchData)) {
342 // Since adding to mvno list, save mvno info
343 mMvnoType = mvnoType;
344 mMvnoMatchData = mvnoMatchData;
352 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
354 if (mAllowAddingApns) {
355 menu.add(0, MENU_NEW, 0,
356 getResources().getString(R.string.menu_new))
357 .setIcon(R.drawable.ic_menu_add_white)
358 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
360 menu.add(0, MENU_RESTORE, 0,
361 getResources().getString(R.string.menu_restore))
362 .setIcon(android.R.drawable.ic_menu_upload);
365 super.onCreateOptionsMenu(menu, inflater);
369 public boolean onOptionsItemSelected(MenuItem item) {
370 switch (item.getItemId()) {
379 return super.onOptionsItemSelected(item);
382 private void addNewApn() {
383 Intent intent = new Intent(Intent.ACTION_INSERT, Telephony.Carriers.CONTENT_URI);
384 int subId = mSubscriptionInfo != null ? mSubscriptionInfo.getSubscriptionId()
385 : SubscriptionManager.INVALID_SUBSCRIPTION_ID;
386 intent.putExtra(SUB_ID, subId);
387 if (!TextUtils.isEmpty(mMvnoType) && !TextUtils.isEmpty(mMvnoMatchData)) {
388 intent.putExtra(MVNO_TYPE, mMvnoType);
389 intent.putExtra(MVNO_MATCH_DATA, mMvnoMatchData);
391 startActivity(intent);
395 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
396 int pos = Integer.parseInt(preference.getKey());
397 Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
398 startActivity(new Intent(Intent.ACTION_EDIT, url));
402 public boolean onPreferenceChange(Preference preference, Object newValue) {
403 Log.d(TAG, "onPreferenceChange(): Preference - " + preference
404 + ", newValue - " + newValue + ", newValue type - "
405 + newValue.getClass());
406 if (newValue instanceof String) {
407 setSelectedApnKey((String) newValue);
413 private void setSelectedApnKey(String key) {
415 ContentResolver resolver = getContentResolver();
417 ContentValues values = new ContentValues();
418 values.put(APN_ID, mSelectedKey);
419 if (TelephonyManager.getDefault().getPhoneCount() > 1 && mImsi != null) {
420 Uri qUri = Uri.withAppendedPath(PREFERRED_MSIM_APN_URI,
421 String.valueOf(mSubscriptionInfo.getSubscriptionId()));
422 qUri = Uri.withAppendedPath(qUri, mImsi);
423 resolver.update(qUri, values, null, null);
425 resolver.update(PREFERAPN_URI, values, null, null);
429 private String getSelectedApnKey() {
433 if (TelephonyManager.getDefault().getPhoneCount() > 1 && mImsi != null
434 && mSubscriptionInfo != null) {
435 uri = Uri.withAppendedPath(PREFERRED_MSIM_APN_URI,
436 String.valueOf(mSubscriptionInfo.getSubscriptionId()));
437 uri = Uri.withAppendedPath(uri, mImsi);
441 try (Cursor cursor = getContentResolver().query(uri, new String[] {"_id"},
442 null, null, Telephony.Carriers.DEFAULT_SORT_ORDER)) {
443 if (cursor != null && cursor.getCount() > 0) {
444 cursor.moveToFirst();
445 key = cursor.getString(ID_INDEX);
451 private boolean restoreDefaultApn() {
452 showDialog(DIALOG_RESTORE_DEFAULTAPN);
453 mRestoreDefaultApnMode = true;
455 if (mRestoreApnUiHandler == null) {
456 mRestoreApnUiHandler = new RestoreApnUiHandler();
459 if (mRestoreApnProcessHandler == null ||
460 mRestoreDefaultApnThread == null) {
461 mRestoreDefaultApnThread = new HandlerThread(
462 "Restore default APN Handler: Process Thread");
463 mRestoreDefaultApnThread.start();
464 mRestoreApnProcessHandler = new RestoreApnProcessHandler(
465 mRestoreDefaultApnThread.getLooper(), mRestoreApnUiHandler);
468 mRestoreApnProcessHandler
469 .sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_START);
473 private class RestoreApnUiHandler extends Handler {
475 public void handleMessage(Message msg) {
477 case EVENT_RESTORE_DEFAULTAPN_COMPLETE:
478 Activity activity = getActivity();
479 if (activity == null) {
480 mRestoreDefaultApnMode = false;
484 getPreferenceScreen().setEnabled(true);
485 mRestoreDefaultApnMode = false;
486 removeDialog(DIALOG_RESTORE_DEFAULTAPN);
489 getResources().getString(
490 R.string.restore_default_apn_completed),
491 Toast.LENGTH_LONG).show();
497 private class RestoreApnProcessHandler extends Handler {
498 private Handler mRestoreApnUiHandler;
500 public RestoreApnProcessHandler(Looper looper, Handler restoreApnUiHandler) {
502 this.mRestoreApnUiHandler = restoreApnUiHandler;
506 public void handleMessage(Message msg) {
508 case EVENT_RESTORE_DEFAULTAPN_START:
509 ContentResolver resolver = getContentResolver();
510 resolver.delete(DEFAULTAPN_URI, null, null);
512 .sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_COMPLETE);
519 public Dialog onCreateDialog(int id) {
520 if (id == DIALOG_RESTORE_DEFAULTAPN) {
521 ProgressDialog dialog = new ProgressDialog(getActivity());
522 dialog.setMessage(getResources().getString(R.string.restore_default_apn));
523 dialog.setCancelable(false);