• 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.apn;
18 
19 import static com.android.settings.network.apn.ApnEditPageProviderKt.INSERT_URL;
20 
21 import android.app.Activity;
22 import android.app.Dialog;
23 import android.app.ProgressDialog;
24 import android.app.settings.SettingsEnums;
25 import android.content.Context;
26 import android.database.Cursor;
27 import android.net.Uri;
28 import android.os.Bundle;
29 import android.os.PersistableBundle;
30 import android.os.UserHandle;
31 import android.os.UserManager;
32 import android.provider.Telephony;
33 import android.telephony.CarrierConfigManager;
34 import android.telephony.SubscriptionManager;
35 import android.telephony.data.ApnSetting;
36 import android.util.Log;
37 import android.view.Menu;
38 import android.view.MenuInflater;
39 import android.view.MenuItem;
40 import android.view.MotionEvent;
41 import android.view.View;
42 import android.widget.Toast;
43 
44 import androidx.annotation.NonNull;
45 import androidx.annotation.Nullable;
46 import androidx.lifecycle.LifecycleOwner;
47 import androidx.preference.Preference;
48 import androidx.preference.PreferenceGroup;
49 
50 import com.android.settings.R;
51 import com.android.settings.RestrictedSettingsFragment;
52 import com.android.settings.network.telephony.SubscriptionRepository;
53 import com.android.settings.spa.SpaActivity;
54 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
55 
56 import kotlin.Unit;
57 
58 import java.util.ArrayList;
59 import java.util.List;
60 
61 /** Handle each different apn setting. */
62 public class ApnSettings extends RestrictedSettingsFragment
63         implements Preference.OnPreferenceChangeListener {
64     static final String TAG = "ApnSettings";
65 
66     public static final String APN_ID = "apn_id";
67     public static final String APN_LIST = "apn_list";
68     public static final String SUB_ID = "sub_id";
69 
70     private static final String[] CARRIERS_PROJECTION = new String[] {
71             Telephony.Carriers._ID,
72             Telephony.Carriers.NAME,
73             Telephony.Carriers.APN,
74             Telephony.Carriers.TYPE,
75             Telephony.Carriers.EDITED_STATUS,
76     };
77 
78     private static final int ID_INDEX = 0;
79     private static final int NAME_INDEX = 1;
80     private static final int APN_INDEX = 2;
81     private static final int TYPES_INDEX = 3;
82     private static final int EDITED_INDEX = 4;
83 
84     private static final int MENU_NEW = Menu.FIRST;
85     private static final int MENU_RESTORE = Menu.FIRST + 1;
86 
87     private static final int DIALOG_RESTORE_DEFAULTAPN = 1001;
88 
89     private boolean mRestoreDefaultApnMode;
90 
91     private UserManager mUserManager;
92     private int mSubId;
93     private PreferredApnRepository mPreferredApnRepository;
94     @Nullable
95     private String mPreferredApnKey;
96 
97     private boolean mUnavailable;
98 
99     private boolean mHideImsApn;
100     private boolean mAllowAddingApns;
101     private boolean mHidePresetApnDetails;
102 
ApnSettings()103     public ApnSettings() {
104         super(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
105     }
106 
107     @Override
getMetricsCategory()108     public int getMetricsCategory() {
109         return SettingsEnums.APN;
110     }
111 
112     @Override
onCreate(Bundle icicle)113     public void onCreate(Bundle icicle) {
114         super.onCreate(icicle);
115         final Activity activity = getActivity();
116         mSubId = activity.getIntent().getIntExtra(SUB_ID,
117                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
118         mPreferredApnRepository = new PreferredApnRepository(activity, mSubId);
119 
120         setIfOnlyAvailableForAdmins(true);
121 
122         final CarrierConfigManager configManager = (CarrierConfigManager)
123                 getSystemService(Context.CARRIER_CONFIG_SERVICE);
124         final PersistableBundle b = configManager.getConfigForSubId(mSubId);
125         mHideImsApn = b.getBoolean(CarrierConfigManager.KEY_HIDE_IMS_APN_BOOL);
126         mAllowAddingApns = b.getBoolean(CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL);
127         if (mAllowAddingApns) {
128             final List<String> readOnlyApnTypes = ApnTypes.getReadOnlyApnTypes(b);
129             // if no apn type can be edited, do not allow adding APNs
130             if (ApnTypes.hasAllApnTypes(readOnlyApnTypes)) {
131                 Log.d(TAG, "not allowing adding APN because all APN types are read only");
132                 mAllowAddingApns = false;
133             }
134         }
135         mHidePresetApnDetails = b.getBoolean(CarrierConfigManager.KEY_HIDE_PRESET_APN_DETAILS_BOOL);
136         mUserManager = UserManager.get(activity);
137     }
138 
139     @Override
onActivityCreated(Bundle savedInstanceState)140     public void onActivityCreated(Bundle savedInstanceState) {
141         super.onActivityCreated(savedInstanceState);
142 
143         getEmptyTextView().setText(com.android.settingslib.R.string.apn_settings_not_available);
144         mUnavailable = isUiRestricted();
145         setHasOptionsMenu(!mUnavailable);
146         if (mUnavailable) {
147             addPreferencesFromResource(R.xml.placeholder_prefs);
148             return;
149         }
150 
151         addPreferencesFromResource(R.xml.apn_settings);
152     }
153 
154     @Override
onViewCreated(@onNull View view, @Nullable Bundle savedInstanceState)155     public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
156         super.onViewCreated(view, savedInstanceState);
157 
158         LifecycleOwner viewLifecycleOwner = getViewLifecycleOwner();
159         new SubscriptionRepository(requireContext())
160                 .collectSubscriptionEnabled(mSubId, viewLifecycleOwner, (isEnabled) -> {
161                     if (!isEnabled) {
162                         Log.d(TAG, "Due to subscription not enabled, closes APN settings page");
163                         finish();
164                     }
165                     return Unit.INSTANCE;
166                 });
167 
168         mPreferredApnRepository.collectPreferredApn(viewLifecycleOwner, (preferredApn) -> {
169             mPreferredApnKey = preferredApn;
170             final PreferenceGroup apnPreferenceList = findPreference(APN_LIST);
171             for (int i = 0; i < apnPreferenceList.getPreferenceCount(); i++) {
172                 ApnPreference apnPreference = (ApnPreference) apnPreferenceList.getPreference(i);
173                 apnPreference.setIsChecked(apnPreference.getKey().equals(preferredApn));
174             }
175             return Unit.INSTANCE;
176         });
177     }
178 
179     @Override
onResume()180     public void onResume() {
181         super.onResume();
182 
183         if (mUnavailable) {
184             return;
185         }
186 
187         if (!mRestoreDefaultApnMode) {
188             fillList();
189         }
190     }
191 
192     @Override
getRestrictionEnforcedAdmin()193     public EnforcedAdmin getRestrictionEnforcedAdmin() {
194         final UserHandle user = UserHandle.of(mUserManager.getProcessUserId());
195         if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, user)
196                 && !mUserManager.hasBaseUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
197                         user)) {
198             return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
199         }
200         return null;
201     }
202 
fillList()203     private void fillList() {
204         final Uri simApnUri = Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI,
205                 String.valueOf(mSubId));
206         final StringBuilder where =
207                 new StringBuilder("NOT (type='ia' AND (apn=\"\" OR apn IS NULL)) AND "
208                 + "user_visible!=0");
209         // Remove Emergency type, users should not mess with that
210         where.append(" AND NOT (type='emergency')");
211 
212         if (mHideImsApn) {
213             where.append(" AND NOT (type='ims')");
214         }
215 
216         final Cursor cursor = getContentResolver().query(simApnUri,
217                 CARRIERS_PROJECTION, where.toString(), null,
218                 Telephony.Carriers.DEFAULT_SORT_ORDER);
219 
220         if (cursor != null) {
221             final PreferenceGroup apnPrefList = findPreference(APN_LIST);
222             apnPrefList.removeAll();
223 
224             final ArrayList<ApnPreference> apnList = new ArrayList<ApnPreference>();
225             final ArrayList<ApnPreference> mmsApnList = new ArrayList<ApnPreference>();
226 
227             cursor.moveToFirst();
228             while (!cursor.isAfterLast()) {
229                 final String name = cursor.getString(NAME_INDEX);
230                 final String apn = cursor.getString(APN_INDEX);
231                 final String key = cursor.getString(ID_INDEX);
232                 final String type = cursor.getString(TYPES_INDEX);
233                 final int edited = cursor.getInt(EDITED_INDEX);
234 
235                 final ApnPreference pref = new ApnPreference(getPrefContext());
236 
237                 pref.setKey(key);
238                 pref.setTitle(name);
239                 pref.setPersistent(false);
240                 pref.setOnPreferenceChangeListener(this);
241                 pref.setSubId(mSubId);
242                 if (mHidePresetApnDetails && edited == Telephony.Carriers.UNEDITED) {
243                     pref.setHideDetails();
244                 } else {
245                     pref.setSummary(apn);
246                 }
247 
248                 final boolean defaultSelectable =
249                         ((type == null) || type.contains(ApnSetting.TYPE_DEFAULT_STRING));
250                 pref.setDefaultSelectable(defaultSelectable);
251                 if (defaultSelectable) {
252                     pref.setIsChecked(key.equals(mPreferredApnKey));
253                     apnList.add(pref);
254                 } else {
255                     mmsApnList.add(pref);
256                 }
257                 cursor.moveToNext();
258             }
259             cursor.close();
260 
261             for (Preference preference : apnList) {
262                 apnPrefList.addPreference(preference);
263             }
264             for (Preference preference : mmsApnList) {
265                 apnPrefList.addPreference(preference);
266             }
267         }
268     }
269 
270     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)271     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
272         if (!mUnavailable) {
273             if (mAllowAddingApns) {
274                 menu.add(0, MENU_NEW, 0,
275                         getResources().getString(R.string.menu_new))
276                         .setIcon(R.drawable.ic_add_24dp)
277                         .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
278             }
279             menu.add(0, MENU_RESTORE, 0,
280                     getResources().getString(R.string.menu_restore))
281                     .setIcon(android.R.drawable.ic_menu_upload);
282         }
283 
284         super.onCreateOptionsMenu(menu, inflater);
285     }
286 
287     @Override
onOptionsItemSelected(MenuItem item)288     public boolean onOptionsItemSelected(MenuItem item) {
289         switch (item.getItemId()) {
290             case MENU_NEW:
291                 addNewApn();
292                 return true;
293             case MENU_RESTORE:
294                 restoreDefaultApn();
295                 return true;
296         }
297         return super.onOptionsItemSelected(item);
298     }
299 
addNewApn()300     private void addNewApn() {
301         String route = ApnEditPageProvider.INSTANCE.getRoute(
302                 INSERT_URL, Telephony.Carriers.CONTENT_URI, mSubId);
303         SpaActivity.startSpaActivity(getContext(), route);
304     }
305 
306     @Override
onPreferenceChange(Preference preference, Object newValue)307     public boolean onPreferenceChange(Preference preference, Object newValue) {
308         Log.d(TAG, "onPreferenceChange(): Preference - " + preference
309                 + ", newValue - " + newValue + ", newValue type - "
310                 + newValue.getClass());
311         if (newValue instanceof String) {
312             mPreferredApnRepository.setPreferredApn((String) newValue);
313         }
314 
315         return true;
316     }
317 
restoreDefaultApn()318     private void restoreDefaultApn() {
319         showDialog(DIALOG_RESTORE_DEFAULTAPN);
320         mRestoreDefaultApnMode = true;
321 
322         mPreferredApnRepository.restorePreferredApn(getViewLifecycleOwner(), () -> {
323             onPreferredApnRestored();
324             return Unit.INSTANCE;
325         });
326     }
327 
onPreferredApnRestored()328     private void onPreferredApnRestored() {
329         final Activity activity = getActivity();
330         if (activity == null) {
331             mRestoreDefaultApnMode = false;
332             return;
333         }
334         fillList();
335         getPreferenceScreen().setEnabled(true);
336         mRestoreDefaultApnMode = false;
337         removeDialog(DIALOG_RESTORE_DEFAULTAPN);
338         Toast.makeText(
339                 activity,
340                 getResources().getString(R.string.restore_default_apn_completed),
341                 Toast.LENGTH_LONG).show();
342     }
343 
344     @Override
onCreateDialog(int id)345     public Dialog onCreateDialog(int id) {
346         if (id == DIALOG_RESTORE_DEFAULTAPN) {
347             final ProgressDialog dialog = new ProgressDialog(getActivity()) {
348                 public boolean onTouchEvent(MotionEvent event) {
349                     return true;
350                 }
351             };
352             dialog.setMessage(getResources().getString(R.string.restore_default_apn));
353             dialog.setCancelable(false);
354             return dialog;
355         }
356         return null;
357     }
358 
359     @Override
getDialogMetricsCategory(int dialogId)360     public int getDialogMetricsCategory(int dialogId) {
361         if (dialogId == DIALOG_RESTORE_DEFAULTAPN) {
362             return SettingsEnums.DIALOG_APN_RESTORE_DEFAULT;
363         }
364         return 0;
365     }
366 }
367