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