1 /* 2 * Copyright (C) 2014 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; 18 19 import static android.content.Context.CARRIER_CONFIG_SERVICE; 20 import static android.content.Context.TELEPHONY_SERVICE; 21 22 import android.Manifest; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.pm.PackageManager.NameNotFoundException; 28 import android.content.res.Resources; 29 import android.os.Bundle; 30 import android.os.PersistableBundle; 31 import android.os.UserHandle; 32 import android.os.UserManager; 33 import android.support.v7.preference.Preference; 34 import android.telephony.CarrierConfigManager; 35 import android.telephony.CellBroadcastMessage; 36 import android.telephony.PhoneStateListener; 37 import android.telephony.ServiceState; 38 import android.telephony.SignalStrength; 39 import android.telephony.SubscriptionInfo; 40 import android.telephony.SubscriptionManager; 41 import android.telephony.TelephonyManager; 42 import android.text.TextUtils; 43 import android.util.Log; 44 import android.view.LayoutInflater; 45 import android.view.View; 46 import android.view.ViewGroup; 47 import android.widget.ListView; 48 import android.widget.TabHost; 49 import android.widget.TabHost.OnTabChangeListener; 50 import android.widget.TabHost.TabContentFactory; 51 import android.widget.TabHost.TabSpec; 52 import android.widget.TabWidget; 53 54 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 55 import com.android.internal.telephony.Phone; 56 import com.android.internal.telephony.PhoneConstantConversions; 57 import com.android.internal.telephony.PhoneFactory; 58 import com.android.settings.R; 59 import com.android.settings.SettingsPreferenceFragment; 60 import com.android.settings.Utils; 61 import com.android.settingslib.DeviceInfoUtils; 62 63 import java.util.List; 64 65 66 /** 67 * Display the following information 68 * # Phone Number 69 * # Network 70 * # Roaming 71 * # Device Id (IMEI in GSM and MEID in CDMA) 72 * # Network type 73 * # Operator info (area update info cell broadcast) 74 * # Signal Strength 75 * 76 */ 77 public class SimStatus extends SettingsPreferenceFragment { 78 private static final String TAG = "SimStatus"; 79 80 private static final String KEY_DATA_STATE = "data_state"; 81 private static final String KEY_SERVICE_STATE = "service_state"; 82 private static final String KEY_OPERATOR_NAME = "operator_name"; 83 private static final String KEY_ROAMING_STATE = "roaming_state"; 84 private static final String KEY_NETWORK_TYPE = "network_type"; 85 private static final String KEY_LATEST_AREA_INFO = "latest_area_info"; 86 private static final String KEY_PHONE_NUMBER = "number"; 87 private static final String KEY_SIGNAL_STRENGTH = "signal_strength"; 88 private static final String KEY_IMEI = "imei"; 89 private static final String KEY_IMEI_SV = "imei_sv"; 90 private static final String KEY_ICCID = "iccid"; 91 92 static private final String CB_AREA_INFO_RECEIVED_ACTION = 93 "com.android.cellbroadcastreceiver.CB_AREA_INFO_RECEIVED"; 94 95 static private final String GET_LATEST_CB_AREA_INFO_ACTION = 96 "com.android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO"; 97 98 static private final String CELL_BROADCAST_RECEIVER_APP = "com.android.cellbroadcastreceiver"; 99 100 private TelephonyManager mTelephonyManager; 101 private CarrierConfigManager mCarrierConfigManager; 102 private Phone mPhone = null; 103 private Resources mRes; 104 private Preference mSignalStrength; 105 private SubscriptionInfo mSir; 106 private boolean mShowLatestAreaInfo; 107 private boolean mShowICCID; 108 109 // Default summary for items 110 private String mDefaultText; 111 112 private TabHost mTabHost; 113 private TabWidget mTabWidget; 114 private ListView mListView; 115 private List<SubscriptionInfo> mSelectableSubInfos; 116 117 private PhoneStateListener mPhoneStateListener; 118 119 // Once the cell broadcast configuration is moved into telephony framework, 120 private final BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() { 121 @Override 122 public void onReceive(Context context, Intent intent) { 123 String action = intent.getAction(); 124 if (CB_AREA_INFO_RECEIVED_ACTION.equals(action)) { 125 Bundle extras = intent.getExtras(); 126 if (extras == null) { 127 return; 128 } 129 CellBroadcastMessage cbMessage = (CellBroadcastMessage) extras.get("message"); 130 if (cbMessage != null && mSir.getSubscriptionId() == cbMessage.getSubId()) { 131 String latestAreaInfo = cbMessage.getMessageBody(); 132 updateAreaInfo(latestAreaInfo); 133 } 134 } 135 } 136 }; 137 138 @Override 139 public void onCreate(Bundle icicle) { 140 super.onCreate(icicle); 141 mTelephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); 142 mCarrierConfigManager = (CarrierConfigManager) getSystemService(CARRIER_CONFIG_SERVICE); 143 144 mSelectableSubInfos = SubscriptionManager.from(getContext()) 145 .getActiveSubscriptionInfoList(); 146 147 addPreferencesFromResource(R.xml.device_info_sim_status); 148 149 mRes = getResources(); 150 mDefaultText = mRes.getString(R.string.device_info_default); 151 // Note - missing in zaku build, be careful later... 152 mSignalStrength = findPreference(KEY_SIGNAL_STRENGTH); 153 } 154 155 @Override 156 public View onCreateView(LayoutInflater inflater, ViewGroup container, 157 Bundle savedInstanceState) { 158 if (mSelectableSubInfos == null) { 159 mSir = null; 160 } else { 161 mSir = mSelectableSubInfos.size() > 0 ? mSelectableSubInfos.get(0) : null; 162 163 if (mSelectableSubInfos.size() > 1) { 164 View view = inflater.inflate(R.layout.icc_lock_tabs, container, false); 165 final ViewGroup prefs_container = (ViewGroup) view.findViewById( 166 R.id.prefs_container); 167 Utils.prepareCustomPreferencesList(container, view, prefs_container, false); 168 View prefs = super.onCreateView(inflater, prefs_container, savedInstanceState); 169 prefs_container.addView(prefs); 170 171 mTabHost = (TabHost) view.findViewById(android.R.id.tabhost); 172 mTabWidget = (TabWidget) view.findViewById(android.R.id.tabs); 173 mListView = (ListView) view.findViewById(android.R.id.list); 174 175 mTabHost.setup(); 176 mTabHost.setOnTabChangedListener(mTabListener); 177 mTabHost.clearAllTabs(); 178 179 for (int i = 0; i < mSelectableSubInfos.size(); i++) { 180 mTabHost.addTab(buildTabSpec(String.valueOf(i), 181 String.valueOf(mSelectableSubInfos.get(i).getDisplayName()))); 182 } 183 return view; 184 } 185 } 186 return super.onCreateView(inflater, container, savedInstanceState); 187 } 188 189 @Override 190 public void onViewCreated(View view, Bundle savedInstanceState) { 191 super.onViewCreated(view, savedInstanceState); 192 193 updatePhoneInfos(); 194 } 195 196 @Override 197 public int getMetricsCategory() { 198 return MetricsEvent.DEVICEINFO_SIM_STATUS; 199 } 200 201 @Override 202 public void onResume() { 203 super.onResume(); 204 if (mPhone != null) { 205 updatePreference(); 206 207 updateSignalStrength(mPhone.getSignalStrength()); 208 updateServiceState(mPhone.getServiceState()); 209 updateDataState(); 210 mTelephonyManager.listen(mPhoneStateListener, 211 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE 212 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS 213 | PhoneStateListener.LISTEN_SERVICE_STATE); 214 if (mShowLatestAreaInfo) { 215 getContext().registerReceiver(mAreaInfoReceiver, 216 new IntentFilter(CB_AREA_INFO_RECEIVED_ACTION), 217 Manifest.permission.RECEIVE_EMERGENCY_BROADCAST, null); 218 // Ask CellBroadcastReceiver to broadcast the latest area info received 219 Intent getLatestIntent = new Intent(GET_LATEST_CB_AREA_INFO_ACTION); 220 getLatestIntent.setPackage(CELL_BROADCAST_RECEIVER_APP); 221 getContext().sendBroadcastAsUser(getLatestIntent, UserHandle.ALL, 222 Manifest.permission.RECEIVE_EMERGENCY_BROADCAST); 223 } 224 } 225 } 226 227 @Override 228 public void onPause() { 229 super.onPause(); 230 231 if (mPhone != null) { 232 mTelephonyManager.listen(mPhoneStateListener, 233 PhoneStateListener.LISTEN_NONE); 234 } 235 if (mShowLatestAreaInfo) { 236 getContext().unregisterReceiver(mAreaInfoReceiver); 237 } 238 } 239 240 /** 241 * Removes the specified preference, if it exists. 242 * @param key the key for the Preference item 243 */ 244 private void removePreferenceFromScreen(String key) { 245 Preference pref = findPreference(key); 246 if (pref != null) { 247 getPreferenceScreen().removePreference(pref); 248 } 249 } 250 251 private void setSummaryText(String key, String text) { 252 if (TextUtils.isEmpty(text)) { 253 text = mDefaultText; 254 } 255 // some preferences may be missing 256 final Preference preference = findPreference(key); 257 if (preference != null) { 258 preference.setSummary(text); 259 } 260 } 261 262 private void updateNetworkType() { 263 // Whether EDGE, UMTS, etc... 264 String networktype = null; 265 final int subId = mSir.getSubscriptionId(); 266 final int actualDataNetworkType = mTelephonyManager.getDataNetworkType( 267 mSir.getSubscriptionId()); 268 final int actualVoiceNetworkType = mTelephonyManager.getVoiceNetworkType( 269 mSir.getSubscriptionId()); 270 if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualDataNetworkType) { 271 networktype = mTelephonyManager.getNetworkTypeName(actualDataNetworkType); 272 } else if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualVoiceNetworkType) { 273 networktype = mTelephonyManager.getNetworkTypeName(actualVoiceNetworkType); 274 } 275 276 boolean show4GForLTE = false; 277 try { 278 Context con = getActivity().createPackageContext("com.android.systemui", 0); 279 int id = con.getResources().getIdentifier("config_show4GForLTE", 280 "bool", "com.android.systemui"); 281 show4GForLTE = con.getResources().getBoolean(id); 282 } catch (NameNotFoundException e) { 283 Log.e(TAG, "NameNotFoundException for show4GFotLTE"); 284 } 285 286 if (networktype != null && networktype.equals("LTE") && show4GForLTE) { 287 networktype = "4G"; 288 } 289 setSummaryText(KEY_NETWORK_TYPE, networktype); 290 } 291 292 private void updateDataState() { 293 final int state = 294 PhoneConstantConversions.convertDataState(mPhone.getDataConnectionState()); 295 296 String display = mRes.getString(R.string.radioInfo_unknown); 297 298 switch (state) { 299 case TelephonyManager.DATA_CONNECTED: 300 display = mRes.getString(R.string.radioInfo_data_connected); 301 break; 302 case TelephonyManager.DATA_SUSPENDED: 303 display = mRes.getString(R.string.radioInfo_data_suspended); 304 break; 305 case TelephonyManager.DATA_CONNECTING: 306 display = mRes.getString(R.string.radioInfo_data_connecting); 307 break; 308 case TelephonyManager.DATA_DISCONNECTED: 309 display = mRes.getString(R.string.radioInfo_data_disconnected); 310 break; 311 } 312 313 setSummaryText(KEY_DATA_STATE, display); 314 } 315 316 private void updateServiceState(ServiceState serviceState) { 317 final int state = serviceState.getState(); 318 String display = mRes.getString(R.string.radioInfo_unknown); 319 320 switch (state) { 321 case ServiceState.STATE_IN_SERVICE: 322 display = mRes.getString(R.string.radioInfo_service_in); 323 break; 324 case ServiceState.STATE_OUT_OF_SERVICE: 325 // Set signal strength to 0 when service state is STATE_OUT_OF_SERVICE 326 mSignalStrength.setSummary("0"); 327 case ServiceState.STATE_EMERGENCY_ONLY: 328 // Set summary string of service state to radioInfo_service_out when 329 // service state is both STATE_OUT_OF_SERVICE & STATE_EMERGENCY_ONLY 330 display = mRes.getString(R.string.radioInfo_service_out); 331 break; 332 case ServiceState.STATE_POWER_OFF: 333 display = mRes.getString(R.string.radioInfo_service_off); 334 // Also set signal strength to 0 335 mSignalStrength.setSummary("0"); 336 break; 337 } 338 339 setSummaryText(KEY_SERVICE_STATE, display); 340 341 if (serviceState.getRoaming()) { 342 setSummaryText(KEY_ROAMING_STATE, mRes.getString(R.string.radioInfo_roaming_in)); 343 } else { 344 setSummaryText(KEY_ROAMING_STATE, mRes.getString(R.string.radioInfo_roaming_not)); 345 } 346 setSummaryText(KEY_OPERATOR_NAME, serviceState.getOperatorAlphaLong()); 347 } 348 349 private void updateAreaInfo(String areaInfo) { 350 if (areaInfo != null) { 351 setSummaryText(KEY_LATEST_AREA_INFO, areaInfo); 352 } 353 } 354 355 void updateSignalStrength(SignalStrength signalStrength) { 356 if (mSignalStrength != null) { 357 final int state = mPhone.getServiceState().getState(); 358 359 if ((ServiceState.STATE_OUT_OF_SERVICE == state) || 360 (ServiceState.STATE_POWER_OFF == state)) { 361 mSignalStrength.setSummary("0"); 362 return; 363 } 364 365 int signalDbm = signalStrength.getDbm(); 366 int signalAsu = signalStrength.getAsuLevel(); 367 368 if (-1 == signalDbm) { 369 signalDbm = 0; 370 } 371 372 if (-1 == signalAsu) { 373 signalAsu = 0; 374 } 375 376 mSignalStrength.setSummary(mRes.getString(R.string.sim_signal_strength, 377 signalDbm, signalAsu)); 378 } 379 } 380 381 private void updatePreference() { 382 if (mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA) { 383 mShowLatestAreaInfo = Resources.getSystem().getBoolean( 384 com.android.internal.R.bool.config_showAreaUpdateInfoSettings); 385 } 386 PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId( 387 mSir.getSubscriptionId()); 388 mShowICCID = carrierConfig.getBoolean( 389 CarrierConfigManager.KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL); 390 391 392 // If formattedNumber is null or empty, it'll display as "Unknown". 393 setSummaryText(KEY_PHONE_NUMBER, 394 DeviceInfoUtils.getFormattedPhoneNumber(getContext(), mSir)); 395 setSummaryText(KEY_IMEI, mPhone.getImei()); 396 setSummaryText(KEY_IMEI_SV, mPhone.getDeviceSvn()); 397 398 if (!mShowICCID) { 399 removePreferenceFromScreen(KEY_ICCID); 400 } else { 401 // Get ICCID, which is SIM serial number 402 String iccid = mTelephonyManager.getSimSerialNumber(mSir.getSubscriptionId()); 403 setSummaryText(KEY_ICCID, iccid); 404 } 405 406 if (!mShowLatestAreaInfo) { 407 removePreferenceFromScreen(KEY_LATEST_AREA_INFO); 408 } 409 } 410 411 private void updatePhoneInfos() { 412 if (mSir != null) { 413 // TODO: http://b/23763013 414 final Phone phone = PhoneFactory.getPhone(SubscriptionManager.getPhoneId( 415 mSir.getSubscriptionId())); 416 if (UserManager.get(getContext()).isAdminUser() 417 && SubscriptionManager.isValidSubscriptionId(mSir.getSubscriptionId())) { 418 if (phone == null) { 419 Log.e(TAG, "Unable to locate a phone object for the given Subscription ID."); 420 return; 421 } 422 423 mPhone = phone; 424 // To avoid register multiple listeners when user changes the tab. 425 if (mPhoneStateListener != null && mTelephonyManager != null) { 426 mTelephonyManager.listen(mPhoneStateListener, 427 PhoneStateListener.LISTEN_NONE); 428 mPhoneStateListener = null; 429 } 430 mPhoneStateListener = new PhoneStateListener(mSir.getSubscriptionId()) { 431 @Override 432 public void onDataConnectionStateChanged(int state) { 433 updateDataState(); 434 updateNetworkType(); 435 } 436 437 @Override 438 public void onSignalStrengthsChanged(SignalStrength signalStrength) { 439 updateSignalStrength(signalStrength); 440 } 441 442 @Override 443 public void onServiceStateChanged(ServiceState serviceState) { 444 updateServiceState(serviceState); 445 } 446 }; 447 } 448 } 449 } 450 private OnTabChangeListener mTabListener = new OnTabChangeListener() { 451 @Override 452 public void onTabChanged(String tabId) { 453 final int slotId = Integer.parseInt(tabId); 454 mSir = mSelectableSubInfos.get(slotId); 455 456 // The User has changed tab; update the SIM information. 457 updatePhoneInfos(); 458 mTelephonyManager.listen(mPhoneStateListener, 459 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE 460 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS 461 | PhoneStateListener.LISTEN_SERVICE_STATE); 462 updateDataState(); 463 updateNetworkType(); 464 updatePreference(); 465 } 466 }; 467 468 private TabContentFactory mEmptyTabContent = new TabContentFactory() { 469 @Override 470 public View createTabContent(String tag) { 471 return new View(mTabHost.getContext()); 472 } 473 }; 474 475 private TabSpec buildTabSpec(String tag, String title) { 476 return mTabHost.newTabSpec(tag).setIndicator(title).setContent( 477 mEmptyTabContent); 478 } 479 } 480