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