1 /* 2 * Copyright (C) 2018 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.telephony.gsm; 18 19 import static androidx.lifecycle.Lifecycle.Event.ON_START; 20 import static androidx.lifecycle.Lifecycle.Event.ON_STOP; 21 22 import android.app.ProgressDialog; 23 import android.app.settings.SettingsEnums; 24 import android.content.Context; 25 import android.os.Bundle; 26 import android.os.Handler; 27 import android.os.HandlerExecutor; 28 import android.os.Looper; 29 import android.os.PersistableBundle; 30 import android.os.SystemClock; 31 import android.provider.Settings; 32 import android.telephony.CarrierConfigManager; 33 import android.telephony.ServiceState; 34 import android.telephony.SubscriptionManager; 35 import android.telephony.TelephonyManager; 36 37 import androidx.annotation.VisibleForTesting; 38 import androidx.lifecycle.Lifecycle; 39 import androidx.lifecycle.LifecycleObserver; 40 import androidx.lifecycle.OnLifecycleEvent; 41 import androidx.preference.Preference; 42 import androidx.preference.PreferenceScreen; 43 import androidx.preference.SwitchPreference; 44 45 import com.android.settings.R; 46 import com.android.settings.core.SubSettingLauncher; 47 import com.android.settings.network.AllowedNetworkTypesListener; 48 import com.android.settings.network.telephony.MobileNetworkUtils; 49 import com.android.settings.network.telephony.NetworkSelectSettings; 50 import com.android.settings.network.telephony.TelephonyTogglePreferenceController; 51 import com.android.settingslib.utils.ThreadUtils; 52 53 import java.util.ArrayList; 54 import java.util.List; 55 import java.util.concurrent.Future; 56 import java.util.concurrent.TimeUnit; 57 58 /** 59 * Preference controller for "Auto Select Network" 60 */ 61 public class AutoSelectPreferenceController extends TelephonyTogglePreferenceController 62 implements LifecycleObserver{ 63 private static final long MINIMUM_DIALOG_TIME_MILLIS = TimeUnit.SECONDS.toMillis(1); 64 65 private final Handler mUiHandler; 66 private PreferenceScreen mPreferenceScreen; 67 private AllowedNetworkTypesListener mAllowedNetworkTypesListener; 68 private TelephonyManager mTelephonyManager; 69 private boolean mOnlyAutoSelectInHome; 70 private List<OnNetworkSelectModeListener> mListeners; 71 @VisibleForTesting 72 ProgressDialog mProgressDialog; 73 @VisibleForTesting 74 SwitchPreference mSwitchPreference; 75 AutoSelectPreferenceController(Context context, String key)76 public AutoSelectPreferenceController(Context context, String key) { 77 super(context, key); 78 mTelephonyManager = context.getSystemService(TelephonyManager.class); 79 mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 80 mListeners = new ArrayList<>(); 81 mUiHandler = new Handler(Looper.getMainLooper()); 82 mAllowedNetworkTypesListener = new AllowedNetworkTypesListener( 83 new HandlerExecutor(mUiHandler)); 84 mAllowedNetworkTypesListener.setAllowedNetworkTypesListener( 85 () -> updatePreference()); 86 } 87 updatePreference()88 private void updatePreference() { 89 if (mPreferenceScreen != null) { 90 displayPreference(mPreferenceScreen); 91 } 92 if (mSwitchPreference != null) { 93 updateState(mSwitchPreference); 94 } 95 } 96 97 @OnLifecycleEvent(ON_START) onStart()98 public void onStart() { 99 mAllowedNetworkTypesListener.register(mContext, mSubId); 100 } 101 102 @OnLifecycleEvent(ON_STOP) onStop()103 public void onStop() { 104 mAllowedNetworkTypesListener.unregister(mContext, mSubId); 105 } 106 107 @Override getAvailabilityStatus(int subId)108 public int getAvailabilityStatus(int subId) { 109 return MobileNetworkUtils.shouldDisplayNetworkSelectOptions(mContext, subId) 110 ? AVAILABLE 111 : CONDITIONALLY_UNAVAILABLE; 112 } 113 114 @Override displayPreference(PreferenceScreen screen)115 public void displayPreference(PreferenceScreen screen) { 116 super.displayPreference(screen); 117 mPreferenceScreen = screen; 118 mSwitchPreference = screen.findPreference(getPreferenceKey()); 119 } 120 121 @Override isChecked()122 public boolean isChecked() { 123 return mTelephonyManager.getNetworkSelectionMode() 124 == TelephonyManager.NETWORK_SELECTION_MODE_AUTO; 125 } 126 127 @Override updateState(Preference preference)128 public void updateState(Preference preference) { 129 super.updateState(preference); 130 131 preference.setSummary(null); 132 final ServiceState serviceState = mTelephonyManager.getServiceState(); 133 if (serviceState == null) { 134 preference.setEnabled(false); 135 return; 136 } 137 138 if (serviceState.getRoaming()) { 139 preference.setEnabled(true); 140 } else { 141 preference.setEnabled(!mOnlyAutoSelectInHome); 142 if (mOnlyAutoSelectInHome) { 143 preference.setSummary(mContext.getString( 144 R.string.manual_mode_disallowed_summary, 145 mTelephonyManager.getSimOperatorName())); 146 } 147 } 148 } 149 150 @Override setChecked(boolean isChecked)151 public boolean setChecked(boolean isChecked) { 152 if (isChecked) { 153 setAutomaticSelectionMode(); 154 return false; 155 } else { 156 final Bundle bundle = new Bundle(); 157 bundle.putInt(Settings.EXTRA_SUB_ID, mSubId); 158 new SubSettingLauncher(mContext) 159 .setDestination(NetworkSelectSettings.class.getName()) 160 .setSourceMetricsCategory(SettingsEnums.MOBILE_NETWORK_SELECT) 161 .setTitleRes(R.string.choose_network_title) 162 .setArguments(bundle) 163 .launch(); 164 return false; 165 } 166 } 167 168 @VisibleForTesting setAutomaticSelectionMode()169 Future setAutomaticSelectionMode() { 170 final long startMillis = SystemClock.elapsedRealtime(); 171 showAutoSelectProgressBar(); 172 mSwitchPreference.setEnabled(false); 173 return ThreadUtils.postOnBackgroundThread(() -> { 174 // set network selection mode in background 175 mTelephonyManager.setNetworkSelectionModeAutomatic(); 176 final int mode = mTelephonyManager.getNetworkSelectionMode(); 177 178 //Update UI in UI thread 179 final long durationMillis = SystemClock.elapsedRealtime() - startMillis; 180 mUiHandler.postDelayed(() -> { 181 mSwitchPreference.setEnabled(true); 182 mSwitchPreference.setChecked( 183 mode == TelephonyManager.NETWORK_SELECTION_MODE_AUTO); 184 for (OnNetworkSelectModeListener lsn : mListeners) { 185 lsn.onNetworkSelectModeChanged(); 186 } 187 dismissProgressBar(); 188 }, Math.max(MINIMUM_DIALOG_TIME_MILLIS - durationMillis, 0)); 189 }); 190 } 191 init(Lifecycle lifecycle, int subId)192 public AutoSelectPreferenceController init(Lifecycle lifecycle, int subId) { 193 mSubId = subId; 194 mTelephonyManager = mContext.getSystemService(TelephonyManager.class) 195 .createForSubscriptionId(mSubId); 196 final PersistableBundle carrierConfig = mContext.getSystemService( 197 CarrierConfigManager.class).getConfigForSubId(mSubId); 198 mOnlyAutoSelectInHome = carrierConfig != null 199 ? carrierConfig.getBoolean( 200 CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL) 201 : false; 202 203 lifecycle.addObserver(this); 204 return this; 205 } 206 addListener(OnNetworkSelectModeListener lsn)207 public AutoSelectPreferenceController addListener(OnNetworkSelectModeListener lsn) { 208 mListeners.add(lsn); 209 210 return this; 211 } 212 showAutoSelectProgressBar()213 private void showAutoSelectProgressBar() { 214 if (mProgressDialog == null) { 215 mProgressDialog = new ProgressDialog(mContext); 216 mProgressDialog.setMessage( 217 mContext.getResources().getString(R.string.register_automatically)); 218 mProgressDialog.setCanceledOnTouchOutside(false); 219 mProgressDialog.setCancelable(false); 220 mProgressDialog.setIndeterminate(true); 221 } 222 mProgressDialog.show(); 223 } 224 dismissProgressBar()225 private void dismissProgressBar() { 226 if (mProgressDialog != null && mProgressDialog.isShowing()) { 227 try { 228 mProgressDialog.dismiss(); 229 } catch (IllegalArgumentException e) { 230 // Ignore exception since the dialog will be gone anyway. 231 } 232 } 233 } 234 235 /** 236 * Callback when network select mode is changed 237 * 238 * @see TelephonyManager#getNetworkSelectionMode() 239 */ 240 public interface OnNetworkSelectModeListener { onNetworkSelectModeChanged()241 void onNetworkSelectModeChanged(); 242 } 243 } 244