1 /* 2 * Copyright (C) 2017 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.deviceinfo.simstatus; 18 19 import static android.content.Context.CARRIER_CONFIG_SERVICE; 20 import static android.content.Context.EUICC_SERVICE; 21 import static android.content.Context.TELEPHONY_SERVICE; 22 import static android.content.Context.TELEPHONY_SUBSCRIPTION_SERVICE; 23 24 import android.Manifest; 25 import android.content.BroadcastReceiver; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.content.res.Resources; 30 import android.os.Bundle; 31 import android.os.PersistableBundle; 32 import android.os.UserHandle; 33 import android.telephony.CarrierConfigManager; 34 import android.telephony.CellBroadcastMessage; 35 import android.telephony.PhoneStateListener; 36 import android.telephony.ServiceState; 37 import android.telephony.SignalStrength; 38 import android.telephony.SubscriptionInfo; 39 import android.telephony.SubscriptionManager; 40 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; 41 import android.telephony.TelephonyManager; 42 import android.telephony.euicc.EuiccManager; 43 import android.text.BidiFormatter; 44 import android.text.TextDirectionHeuristics; 45 import android.text.TextUtils; 46 47 import androidx.annotation.NonNull; 48 import androidx.annotation.VisibleForTesting; 49 50 import com.android.settings.R; 51 import com.android.settingslib.DeviceInfoUtils; 52 import com.android.settingslib.Utils; 53 import com.android.settingslib.core.lifecycle.Lifecycle; 54 import com.android.settingslib.core.lifecycle.LifecycleObserver; 55 import com.android.settingslib.core.lifecycle.events.OnPause; 56 import com.android.settingslib.core.lifecycle.events.OnResume; 57 58 public class SimStatusDialogController implements LifecycleObserver, OnResume, OnPause { 59 60 private final static String TAG = "SimStatusDialogCtrl"; 61 62 @VisibleForTesting 63 final static int NETWORK_PROVIDER_VALUE_ID = R.id.operator_name_value; 64 @VisibleForTesting 65 final static int PHONE_NUMBER_VALUE_ID = R.id.number_value; 66 @VisibleForTesting 67 final static int CELLULAR_NETWORK_STATE = R.id.data_state_value; 68 @VisibleForTesting 69 final static int OPERATOR_INFO_LABEL_ID = R.id.latest_area_info_label; 70 @VisibleForTesting 71 final static int OPERATOR_INFO_VALUE_ID = R.id.latest_area_info_value; 72 @VisibleForTesting 73 final static int SERVICE_STATE_VALUE_ID = R.id.service_state_value; 74 @VisibleForTesting 75 final static int SIGNAL_STRENGTH_LABEL_ID = R.id.signal_strength_label; 76 @VisibleForTesting 77 final static int SIGNAL_STRENGTH_VALUE_ID = R.id.signal_strength_value; 78 @VisibleForTesting 79 final static int CELL_VOICE_NETWORK_TYPE_VALUE_ID = R.id.voice_network_type_value; 80 @VisibleForTesting 81 final static int CELL_DATA_NETWORK_TYPE_VALUE_ID = R.id.data_network_type_value; 82 @VisibleForTesting 83 final static int ROAMING_INFO_VALUE_ID = R.id.roaming_state_value; 84 @VisibleForTesting 85 final static int ICCID_INFO_LABEL_ID = R.id.icc_id_label; 86 @VisibleForTesting 87 final static int ICCID_INFO_VALUE_ID = R.id.icc_id_value; 88 @VisibleForTesting 89 final static int EID_INFO_VALUE_ID = R.id.esim_id_value; 90 @VisibleForTesting 91 final static int IMS_REGISTRATION_STATE_LABEL_ID = R.id.ims_reg_state_label; 92 @VisibleForTesting 93 final static int IMS_REGISTRATION_STATE_VALUE_ID = R.id.ims_reg_state_value; 94 95 private final static String CB_AREA_INFO_RECEIVED_ACTION = 96 "com.android.cellbroadcastreceiver.CB_AREA_INFO_RECEIVED"; 97 private final static String GET_LATEST_CB_AREA_INFO_ACTION = 98 "com.android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO"; 99 private final static String CELL_BROADCAST_RECEIVER_APP = "com.android.cellbroadcastreceiver"; 100 101 private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener = 102 new OnSubscriptionsChangedListener() { 103 @Override 104 public void onSubscriptionsChanged() { 105 mSubscriptionInfo = mSubscriptionManager.getActiveSubscriptionInfo( 106 mSubscriptionInfo.getSubscriptionId()); 107 updateNetworkProvider(); 108 } 109 }; 110 111 private SubscriptionInfo mSubscriptionInfo; 112 113 private final SimStatusDialogFragment mDialog; 114 private final TelephonyManager mTelephonyManager; 115 private final SubscriptionManager mSubscriptionManager; 116 private final CarrierConfigManager mCarrierConfigManager; 117 private final EuiccManager mEuiccManager; 118 private final Resources mRes; 119 private final Context mContext; 120 121 private boolean mShowLatestAreaInfo; 122 123 private final BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() { 124 @Override 125 public void onReceive(Context context, Intent intent) { 126 final String action = intent.getAction(); 127 if (TextUtils.equals(action, CB_AREA_INFO_RECEIVED_ACTION)) { 128 final Bundle extras = intent.getExtras(); 129 if (extras == null) { 130 return; 131 } 132 final CellBroadcastMessage cbMessage = (CellBroadcastMessage) extras.get("message"); 133 if (cbMessage != null 134 && mSubscriptionInfo.getSubscriptionId() == cbMessage.getSubId()) { 135 final String latestAreaInfo = cbMessage.getMessageBody(); 136 mDialog.setText(OPERATOR_INFO_VALUE_ID, latestAreaInfo); 137 } 138 } 139 } 140 }; 141 142 private PhoneStateListener mPhoneStateListener; 143 SimStatusDialogController(@onNull SimStatusDialogFragment dialog, Lifecycle lifecycle, int slotId)144 public SimStatusDialogController(@NonNull SimStatusDialogFragment dialog, Lifecycle lifecycle, 145 int slotId) { 146 mDialog = dialog; 147 mContext = dialog.getContext(); 148 mSubscriptionInfo = getPhoneSubscriptionInfo(slotId); 149 mTelephonyManager = mContext.getSystemService(TelephonyManager.class); 150 mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); 151 mEuiccManager = mContext.getSystemService(EuiccManager.class); 152 mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); 153 154 mRes = mContext.getResources(); 155 156 if (lifecycle != null) { 157 lifecycle.addObserver(this); 158 } 159 } 160 initialize()161 public void initialize() { 162 updateEid(); 163 164 if (mSubscriptionInfo == null) { 165 return; 166 } 167 168 mPhoneStateListener = getPhoneStateListener(); 169 updateNetworkProvider(); 170 171 final ServiceState serviceState = getCurrentServiceState(); 172 updatePhoneNumber(); 173 updateLatestAreaInfo(); 174 updateServiceState(serviceState); 175 updateSignalStrength(getSignalStrength()); 176 updateNetworkType(); 177 updateRoamingStatus(serviceState); 178 updateIccidNumber(); 179 updateImsRegistrationState(); 180 } 181 182 @Override onResume()183 public void onResume() { 184 if (mSubscriptionInfo == null) { 185 return; 186 } 187 188 mTelephonyManager.createForSubscriptionId(mSubscriptionInfo.getSubscriptionId()) 189 .listen(mPhoneStateListener, 190 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE 191 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS 192 | PhoneStateListener.LISTEN_SERVICE_STATE); 193 mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener); 194 195 if (mShowLatestAreaInfo) { 196 mContext.registerReceiver(mAreaInfoReceiver, 197 new IntentFilter(CB_AREA_INFO_RECEIVED_ACTION), 198 Manifest.permission.RECEIVE_EMERGENCY_BROADCAST, null /* scheduler */); 199 // Ask CellBroadcastReceiver to broadcast the latest area info received 200 final Intent getLatestIntent = new Intent(GET_LATEST_CB_AREA_INFO_ACTION); 201 getLatestIntent.setPackage(CELL_BROADCAST_RECEIVER_APP); 202 mContext.sendBroadcastAsUser(getLatestIntent, UserHandle.ALL, 203 Manifest.permission.RECEIVE_EMERGENCY_BROADCAST); 204 } 205 } 206 207 @Override onPause()208 public void onPause() { 209 if (mSubscriptionInfo == null) { 210 return; 211 } 212 213 mSubscriptionManager.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener); 214 mTelephonyManager.createForSubscriptionId(mSubscriptionInfo.getSubscriptionId()) 215 .listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); 216 217 if (mShowLatestAreaInfo) { 218 mContext.unregisterReceiver(mAreaInfoReceiver); 219 } 220 } 221 updateNetworkProvider()222 private void updateNetworkProvider() { 223 final CharSequence carrierName = 224 mSubscriptionInfo != null ? mSubscriptionInfo.getCarrierName() : null; 225 mDialog.setText(NETWORK_PROVIDER_VALUE_ID, carrierName); 226 } 227 updatePhoneNumber()228 private void updatePhoneNumber() { 229 // If formattedNumber is null or empty, it'll display as "Unknown". 230 mDialog.setText(PHONE_NUMBER_VALUE_ID, BidiFormatter.getInstance().unicodeWrap( 231 getPhoneNumber(), TextDirectionHeuristics.LTR)); 232 } 233 updateDataState(int state)234 private void updateDataState(int state) { 235 String networkStateValue; 236 237 switch (state) { 238 case TelephonyManager.DATA_CONNECTED: 239 networkStateValue = mRes.getString(R.string.radioInfo_data_connected); 240 break; 241 case TelephonyManager.DATA_SUSPENDED: 242 networkStateValue = mRes.getString(R.string.radioInfo_data_suspended); 243 break; 244 case TelephonyManager.DATA_CONNECTING: 245 networkStateValue = mRes.getString(R.string.radioInfo_data_connecting); 246 break; 247 case TelephonyManager.DATA_DISCONNECTED: 248 networkStateValue = mRes.getString(R.string.radioInfo_data_disconnected); 249 break; 250 default: 251 networkStateValue = mRes.getString(R.string.radioInfo_unknown); 252 break; 253 } 254 255 mDialog.setText(CELLULAR_NETWORK_STATE, networkStateValue); 256 } 257 258 updateLatestAreaInfo()259 private void updateLatestAreaInfo() { 260 mShowLatestAreaInfo = Resources.getSystem().getBoolean( 261 com.android.internal.R.bool.config_showAreaUpdateInfoSettings) 262 && mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA; 263 264 if (!mShowLatestAreaInfo) { 265 mDialog.removeSettingFromScreen(OPERATOR_INFO_LABEL_ID); 266 mDialog.removeSettingFromScreen(OPERATOR_INFO_VALUE_ID); 267 } 268 } 269 updateServiceState(ServiceState serviceState)270 private void updateServiceState(ServiceState serviceState) { 271 final int state = Utils.getCombinedServiceState(serviceState); 272 if (!Utils.isInService(serviceState)) { 273 resetSignalStrength(); 274 } 275 276 String serviceStateValue; 277 278 switch (state) { 279 case ServiceState.STATE_IN_SERVICE: 280 serviceStateValue = mRes.getString(R.string.radioInfo_service_in); 281 break; 282 case ServiceState.STATE_OUT_OF_SERVICE: 283 case ServiceState.STATE_EMERGENCY_ONLY: 284 // Set summary string of service state to radioInfo_service_out when 285 // service state is both STATE_OUT_OF_SERVICE & STATE_EMERGENCY_ONLY 286 serviceStateValue = mRes.getString(R.string.radioInfo_service_out); 287 break; 288 case ServiceState.STATE_POWER_OFF: 289 serviceStateValue = mRes.getString(R.string.radioInfo_service_off); 290 break; 291 default: 292 serviceStateValue = mRes.getString(R.string.radioInfo_unknown); 293 break; 294 } 295 296 mDialog.setText(SERVICE_STATE_VALUE_ID, serviceStateValue); 297 } 298 updateSignalStrength(SignalStrength signalStrength)299 private void updateSignalStrength(SignalStrength signalStrength) { 300 if (signalStrength == null) { 301 return; 302 } 303 final int subscriptionId = mSubscriptionInfo.getSubscriptionId(); 304 final PersistableBundle carrierConfig = 305 mCarrierConfigManager.getConfigForSubId(subscriptionId); 306 // by default we show the signal strength 307 boolean showSignalStrength = true; 308 if (carrierConfig != null) { 309 showSignalStrength = carrierConfig.getBoolean( 310 CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL); 311 } 312 if (!showSignalStrength) { 313 mDialog.removeSettingFromScreen(SIGNAL_STRENGTH_LABEL_ID); 314 mDialog.removeSettingFromScreen(SIGNAL_STRENGTH_VALUE_ID); 315 return; 316 } 317 318 ServiceState serviceState = getCurrentServiceState(); 319 if (serviceState == null || !Utils.isInService(serviceState)) { 320 return; 321 } 322 323 int signalDbm = getDbm(signalStrength); 324 int signalAsu = getAsuLevel(signalStrength); 325 326 if (signalDbm == -1) { 327 signalDbm = 0; 328 } 329 330 if (signalAsu == -1) { 331 signalAsu = 0; 332 } 333 334 mDialog.setText(SIGNAL_STRENGTH_VALUE_ID, mRes.getString(R.string.sim_signal_strength, 335 signalDbm, signalAsu)); 336 } 337 resetSignalStrength()338 private void resetSignalStrength() { 339 mDialog.setText(SIGNAL_STRENGTH_VALUE_ID, "0"); 340 } 341 updateNetworkType()342 private void updateNetworkType() { 343 // Whether EDGE, UMTS, etc... 344 String dataNetworkTypeName = null; 345 String voiceNetworkTypeName = null; 346 final int subId = mSubscriptionInfo.getSubscriptionId(); 347 final int actualDataNetworkType = mTelephonyManager.getDataNetworkType(subId); 348 final int actualVoiceNetworkType = mTelephonyManager.getVoiceNetworkType(subId); 349 if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualDataNetworkType) { 350 dataNetworkTypeName = mTelephonyManager.getNetworkTypeName(actualDataNetworkType); 351 } 352 if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualVoiceNetworkType) { 353 voiceNetworkTypeName = mTelephonyManager.getNetworkTypeName(actualVoiceNetworkType); 354 } 355 356 boolean show4GForLTE = false; 357 final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId); 358 if (carrierConfig != null) { 359 show4GForLTE = carrierConfig.getBoolean( 360 CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL); 361 } 362 363 if (show4GForLTE) { 364 if ("LTE".equals(dataNetworkTypeName)) { 365 dataNetworkTypeName = "4G"; 366 } 367 if ("LTE".equals(voiceNetworkTypeName)) { 368 voiceNetworkTypeName = "4G"; 369 } 370 } 371 372 mDialog.setText(CELL_VOICE_NETWORK_TYPE_VALUE_ID, voiceNetworkTypeName); 373 mDialog.setText(CELL_DATA_NETWORK_TYPE_VALUE_ID, dataNetworkTypeName); 374 } 375 updateRoamingStatus(ServiceState serviceState)376 private void updateRoamingStatus(ServiceState serviceState) { 377 if (serviceState.getRoaming()) { 378 mDialog.setText(ROAMING_INFO_VALUE_ID, mRes.getString(R.string.radioInfo_roaming_in)); 379 } else { 380 mDialog.setText(ROAMING_INFO_VALUE_ID, mRes.getString(R.string.radioInfo_roaming_not)); 381 } 382 } 383 updateIccidNumber()384 private void updateIccidNumber() { 385 final int subscriptionId = mSubscriptionInfo.getSubscriptionId(); 386 final PersistableBundle carrierConfig = 387 mCarrierConfigManager.getConfigForSubId(subscriptionId); 388 // do not show iccid by default 389 boolean showIccId = false; 390 if (carrierConfig != null) { 391 showIccId = carrierConfig.getBoolean( 392 CarrierConfigManager.KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL); 393 } 394 if (!showIccId) { 395 mDialog.removeSettingFromScreen(ICCID_INFO_LABEL_ID); 396 mDialog.removeSettingFromScreen(ICCID_INFO_VALUE_ID); 397 } else { 398 mDialog.setText(ICCID_INFO_VALUE_ID, getSimSerialNumber(subscriptionId)); 399 } 400 } 401 updateEid()402 private void updateEid() { 403 if (mEuiccManager.isEnabled()) { 404 mDialog.setText(EID_INFO_VALUE_ID, mEuiccManager.getEid()); 405 } else { 406 mDialog.removeSettingFromScreen(EID_INFO_VALUE_ID); 407 } 408 } 409 updateImsRegistrationState()410 private void updateImsRegistrationState() { 411 final int subscriptionId = mSubscriptionInfo.getSubscriptionId(); 412 final PersistableBundle carrierConfig = 413 mCarrierConfigManager.getConfigForSubId(subscriptionId); 414 final boolean showImsRegState = carrierConfig == null ? false : 415 carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL); 416 if (showImsRegState) { 417 final boolean isImsRegistered = mTelephonyManager.isImsRegistered(subscriptionId); 418 mDialog.setText(IMS_REGISTRATION_STATE_VALUE_ID, mRes.getString(isImsRegistered ? 419 R.string.ims_reg_status_registered : R.string.ims_reg_status_not_registered)); 420 } else { 421 mDialog.removeSettingFromScreen(IMS_REGISTRATION_STATE_LABEL_ID); 422 mDialog.removeSettingFromScreen(IMS_REGISTRATION_STATE_VALUE_ID); 423 } 424 } 425 getPhoneSubscriptionInfo(int slotId)426 private SubscriptionInfo getPhoneSubscriptionInfo(int slotId) { 427 return SubscriptionManager.from(mContext).getActiveSubscriptionInfoForSimSlotIndex(slotId); 428 } 429 430 @VisibleForTesting getCurrentServiceState()431 ServiceState getCurrentServiceState() { 432 return mTelephonyManager.getServiceStateForSubscriber( 433 mSubscriptionInfo.getSubscriptionId()); 434 } 435 getDbm(SignalStrength signalStrength)436 private int getDbm(SignalStrength signalStrength) { 437 return signalStrength.getDbm(); 438 } 439 getAsuLevel(SignalStrength signalStrength)440 private int getAsuLevel(SignalStrength signalStrength) { 441 return signalStrength.getAsuLevel(); 442 } 443 444 @VisibleForTesting getPhoneStateListener()445 PhoneStateListener getPhoneStateListener() { 446 return new PhoneStateListener() { 447 @Override 448 public void onDataConnectionStateChanged(int state) { 449 updateDataState(state); 450 updateNetworkType(); 451 } 452 453 @Override 454 public void onSignalStrengthsChanged(SignalStrength signalStrength) { 455 updateSignalStrength(signalStrength); 456 } 457 458 @Override 459 public void onServiceStateChanged(ServiceState serviceState) { 460 updateNetworkProvider(); 461 updateServiceState(serviceState); 462 updateRoamingStatus(serviceState); 463 } 464 }; 465 } 466 467 @VisibleForTesting 468 String getPhoneNumber() { 469 return DeviceInfoUtils.getFormattedPhoneNumber(mContext, mSubscriptionInfo); 470 } 471 472 @VisibleForTesting 473 SignalStrength getSignalStrength() { 474 return mTelephonyManager.getSignalStrength(); 475 } 476 477 @VisibleForTesting 478 String getSimSerialNumber(int subscriptionId) { 479 return mTelephonyManager.getSimSerialNumber(subscriptionId); 480 } 481 } 482