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