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);
171 mUm = (UserManager) getSystemService(Context.USER_SERVICE);
173 mMobileStateFilter = new IntentFilter(
174 TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
176 if (!mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
177 setHasOptionsMenu(true);
180 mSubscriptionInfo = SubscriptionManager.from(activity).getActiveSubscriptionInfo(subId);
181 mUiccController = UiccController.getInstance();
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);
191 public void onActivityCreated(Bundle savedInstanceState) {
192 super.onActivityCreated(savedInstanceState);
194 TextView empty = (TextView) getView().findViewById(android.R.id.empty);
196 empty.setText(R.string.apn_settings_not_available);
197 getListView().setEmptyView(empty);
200 if (mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)
201 || UserHandle.myUserId()!= UserHandle.USER_OWNER) {
203 setPreferenceScreen(new PreferenceScreen(getActivity(), null));
207 addPreferencesFromResource(R.xml.apn_settings);
209 getListView().setItemsCanFocus(true);
213 public void onResume() {
220 getActivity().registerReceiver(mMobileStateReceiver, mMobileStateFilter);
222 if (!mRestoreDefaultApnMode) {
228 public void onPause() {
235 getActivity().unregisterReceiver(mMobileStateReceiver);
239 public void onDestroy() {
242 if (mRestoreDefaultApnThread != null) {
243 mRestoreDefaultApnThread.quit();
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");
257 where.append(" AND NOT (type='ims')");
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);
264 if (cursor != null) {
266 if (mUiccController != null && mSubscriptionInfo != null) {
267 r = mUiccController.getIccRecords(SubscriptionManager.getPhoneId(
268 mSubscriptionInfo.getSubscriptionId()), UiccController.APP_FAM_3GPP);
270 PreferenceGroup apnList = (PreferenceGroup) findPreference("apn_list");
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>();
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);
289 ApnPreference pref = new ApnPreference(getActivity());
291 pref.setApnReadOnly(readOnly);
294 pref.setSummary(apn);
295 pref.setPersistent(false);
296 pref.setOnPreferenceChangeListener(this);
298 boolean selectable = ((type == null) || !type.equals("mms"));
299 pref.setSelectable(selectable);
301 if ((mSelectedKey != null) && mSelectedKey.equals(key)) {
303 isSelectedKeyMatch = true;
304 Log.d(TAG, "find select key = " + mSelectedKey);
306 addApnToList(pref, mnoApnList, mvnoApnList, r, mvnoType, mvnoMatchData);
308 addApnToList(pref, mnoMmsApnList, mvnoMmsApnList, r, mvnoType, mvnoMatchData);
314 if (!mvnoApnList.isEmpty()) {
315 mnoApnList = mvnoApnList;
316 mnoMmsApnList = mvnoMmsApnList;
318 // Also save the mvno info
321 for (Preference preference : mnoApnList) {
322 apnList.addPreference(preference);
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);
329 setSelectedApnKey(pref.getKey());
330 Log.d(TAG, "set key to " +pref.getKey());
333 for (Preference preference : mnoMmsApnList) {
334 apnList.addPreference(preference);
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)) {
345 // Since adding to mvno list, save mvno info
346 mMvnoType = mvnoType;
347 mMvnoMatchData = mvnoMatchData;
355 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
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);
363 menu.add(0, MENU_RESTORE, 0,
364 getResources().getString(R.string.menu_restore))
365 .setIcon(android.R.drawable.ic_menu_upload);
368 super.onCreateOptionsMenu(menu, inflater);
372 public boolean onOptionsItemSelected(MenuItem item) {
373 switch (item.getItemId()) {
382 return super.onOptionsItemSelected(item);
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);
394 startActivity(intent);
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));
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);
416 private void setSelectedApnKey(String key) {
418 ContentResolver resolver = getContentResolver();
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);
428 resolver.update(PREFERAPN_URI, values, null, null);
432 private String getSelectedApnKey() {
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);
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);
453 private boolean restoreDefaultApn() {
454 showDialog(DIALOG_RESTORE_DEFAULTAPN);
455 mRestoreDefaultApnMode = true;
457 if (mRestoreApnUiHandler == null) {
458 mRestoreApnUiHandler = new RestoreApnUiHandler();
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);
470 mRestoreApnProcessHandler
471 .sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_START);
475 private class RestoreApnUiHandler extends Handler {
477 public void handleMessage(Message msg) {
479 case EVENT_RESTORE_DEFAULTAPN_COMPLETE:
480 Activity activity = getActivity();
481 if (activity == null) {
482 mRestoreDefaultApnMode = false;
486 getPreferenceScreen().setEnabled(true);
487 mRestoreDefaultApnMode = false;
488 removeDialog(DIALOG_RESTORE_DEFAULTAPN);
491 getResources().getString(
492 R.string.restore_default_apn_completed),
493 Toast.LENGTH_LONG).show();
499 private class RestoreApnProcessHandler extends Handler {
500 private Handler mRestoreApnUiHandler;
502 public RestoreApnProcessHandler(Looper looper, Handler restoreApnUiHandler) {
504 this.mRestoreApnUiHandler = restoreApnUiHandler;
508 public void handleMessage(Message msg) {
510 case EVENT_RESTORE_DEFAULTAPN_START:
511 ContentResolver resolver = getContentResolver();
512 resolver.delete(DEFAULTAPN_URI, null, null);
514 .sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_COMPLETE);
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);