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 17package com.android.settings.deviceinfo; 18 19import static android.content.Context.CARRIER_CONFIG_SERVICE; 20import static android.content.Context.TELEPHONY_SERVICE; 21 22import android.content.BroadcastReceiver; 23import android.content.Context; 24import android.content.Intent; 25import android.content.IntentFilter; 26import android.content.pm.PackageManager.NameNotFoundException; 27import android.content.res.Resources; 28import android.os.Bundle; 29import android.os.PersistableBundle; 30import android.os.UserHandle; 31import android.os.UserManager; 32import android.support.v7.preference.Preference; 33import android.telephony.CarrierConfigManager; 34import android.telephony.CellBroadcastMessage; 35import android.telephony.PhoneNumberUtils; 36import android.telephony.PhoneStateListener; 37import android.telephony.ServiceState; 38import android.telephony.SignalStrength; 39import android.telephony.SubscriptionInfo; 40import android.telephony.SubscriptionManager; 41import android.telephony.TelephonyManager; 42import android.text.TextUtils; 43import android.util.Log; 44import android.view.LayoutInflater; 45import android.view.View; 46import android.view.ViewGroup; 47import android.widget.ListView; 48import android.widget.TabHost; 49import android.widget.TabHost.OnTabChangeListener; 50import android.widget.TabHost.TabContentFactory; 51import android.widget.TabHost.TabSpec; 52import android.widget.TabWidget; 53 54import com.android.internal.logging.MetricsProto.MetricsEvent; 55import com.android.internal.telephony.DefaultPhoneNotifier; 56import com.android.internal.telephony.Phone; 57import com.android.internal.telephony.PhoneFactory; 58import com.android.settings.R; 59import com.android.settings.SettingsPreferenceFragment; 60import com.android.settings.Utils; 61 62import java.util.List; 63 64 65/** 66 * Display the following information 67 * # Phone Number 68 * # Network 69 * # Roaming 70 * # Device Id (IMEI in GSM and MEID in CDMA) 71 * # Network type 72 * # Operator info (area info cell broadcast for Brazil) 73 * # Signal Strength 74 * 75 */ 76public class SimStatus extends SettingsPreferenceFragment { 77 private static final String TAG = "SimStatus"; 78 79 private static final String KEY_DATA_STATE = "data_state"; 80 private static final String KEY_SERVICE_STATE = "service_state"; 81 private static final String KEY_OPERATOR_NAME = "operator_name"; 82 private static final String KEY_ROAMING_STATE = "roaming_state"; 83 private static final String KEY_NETWORK_TYPE = "network_type"; 84 private static final String KEY_LATEST_AREA_INFO = "latest_area_info"; 85 private static final String KEY_PHONE_NUMBER = "number"; 86 private static final String KEY_SIGNAL_STRENGTH = "signal_strength"; 87 private static final String KEY_IMEI = "imei"; 88 private static final String KEY_IMEI_SV = "imei_sv"; 89 private static final String KEY_ICCID = "iccid"; 90 private static final String COUNTRY_ABBREVIATION_BRAZIL = "br"; 91 92 static final String CB_AREA_INFO_RECEIVED_ACTION = 93 "android.cellbroadcastreceiver.CB_AREA_INFO_RECEIVED"; 94 95 static final String GET_LATEST_CB_AREA_INFO_ACTION = 96 "android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO"; 97 98 // Require the sender to have this permission to prevent third-party spoofing. 99 static final String CB_AREA_INFO_SENDER_PERMISSION = 100 "android.permission.RECEIVE_EMERGENCY_BROADCAST"; 101 102 103 private TelephonyManager mTelephonyManager; 104 private CarrierConfigManager mCarrierConfigManager; 105 private Phone mPhone = null; 106 private Resources mRes; 107 private Preference mSignalStrength; 108 private SubscriptionInfo mSir; 109 private boolean mShowLatestAreaInfo; 110 private boolean mShowICCID; 111 112 // Default summary for items 113 private String mDefaultText; 114 115 private TabHost mTabHost; 116 private TabWidget mTabWidget; 117 private ListView mListView; 118 private List<SubscriptionInfo> mSelectableSubInfos; 119 120 private PhoneStateListener mPhoneStateListener; 121 private BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() { 122 @Override 123 public void onReceive(Context context, Intent intent) { 124 String action = intent.getAction(); 125 if (CB_AREA_INFO_RECEIVED_ACTION.equals(action)) { 126 Bundle extras = intent.getExtras(); 127 if (extras == null) { 128 return; 129 } 130 CellBroadcastMessage cbMessage = (CellBroadcastMessage) extras.get("message"); 131 if (cbMessage != null && cbMessage.getServiceCategory() == 50) { 132 String latestAreaInfo = cbMessage.getMessageBody(); 133 updateAreaInfo(latestAreaInfo); 134 } 135 } 136 } 137 }; 138 139 @Override 140 public void onCreate(Bundle icicle) { 141 super.onCreate(icicle); 142 mTelephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); 143 mCarrierConfigManager = (CarrierConfigManager) getSystemService(CARRIER_CONFIG_SERVICE); 144 145 mSelectableSubInfos = SubscriptionManager.from(getContext()) 146 .getActiveSubscriptionInfoList(); 147 148 addPreferencesFromResource(R.xml.device_info_sim_status); 149 150 mRes = getResources(); 151 mDefaultText = mRes.getString(R.string.device_info_default); 152 // Note - missing in zaku build, be careful later... 153 mSignalStrength = findPreference(KEY_SIGNAL_STRENGTH); 154 } 155 156 @Override 157 public View onCreateView(LayoutInflater inflater, ViewGroup container, 158 Bundle savedInstanceState) { 159 if (mSelectableSubInfos == null) { 160 mSir = null; 161 } else { 162 mSir = mSelectableSubInfos.size() > 0 ? mSelectableSubInfos.get(0) : null; 163 164 if (mSelectableSubInfos.size() > 1) { 165 View view = inflater.inflate(R.layout.icc_lock_tabs, container, false); 166 final ViewGroup prefs_container = (ViewGroup) view.findViewById( 167 R.id.prefs_container); 168 Utils.prepareCustomPreferencesList(container, view, prefs_container, false); 169 View prefs = super.onCreateView(inflater, prefs_container, savedInstanceState); 170 prefs_container.addView(prefs); 171 172 mTabHost = (TabHost) view.findViewById(android.R.id.tabhost); 173 mTabWidget = (TabWidget) view.findViewById(android.R.id.tabs); 174 mListView = (ListView) view.findViewById(android.R.id.list); 175 176 mTabHost.setup(); 177 mTabHost.setOnTabChangedListener(mTabListener); 178 mTabHost.clearAllTabs(); 179 180 for (int i = 0; i < mSelectableSubInfos.size(); i++) { 181 mTabHost.addTab(buildTabSpec(String.valueOf(i), 182 String.valueOf(mSelectableSubInfos.get(i).getDisplayName()))); 183 } 184 return view; 185 } 186 } 187 return super.onCreateView(inflater, container, savedInstanceState); 188 } 189 190 @Override 191 public void onViewCreated(View view, Bundle savedInstanceState) { 192 super.onViewCreated(view, savedInstanceState); 193 194 updatePhoneInfos(); 195 } 196 197 @Override 198 protected int getMetricsCategory() { 199 return MetricsEvent.DEVICEINFO_SIM_STATUS; 200 } 201 202 @Override 203 public void onResume() { 204 super.onResume(); 205 if (mPhone != null) { 206 updatePreference(); 207 208 updateSignalStrength(mPhone.getSignalStrength()); 209 updateServiceState(mPhone.getServiceState()); 210 updateDataState(); 211 mTelephonyManager.listen(mPhoneStateListener, 212 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE 213 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS 214 | PhoneStateListener.LISTEN_SERVICE_STATE); 215 if (mShowLatestAreaInfo) { 216 getContext().registerReceiver(mAreaInfoReceiver, 217 new IntentFilter(CB_AREA_INFO_RECEIVED_ACTION), 218 CB_AREA_INFO_SENDER_PERMISSION, null); 219 // Ask CellBroadcastReceiver to broadcast the latest area info received 220 Intent getLatestIntent = new Intent(GET_LATEST_CB_AREA_INFO_ACTION); 221 getContext().sendBroadcastAsUser(getLatestIntent, UserHandle.ALL, 222 CB_AREA_INFO_SENDER_PERMISSION); 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 DefaultPhoneNotifier.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 Resources r = getResources(); 359 360 if ((ServiceState.STATE_OUT_OF_SERVICE == state) || 361 (ServiceState.STATE_POWER_OFF == state)) { 362 mSignalStrength.setSummary("0"); 363 return; 364 } 365 366 int signalDbm = signalStrength.getDbm(); 367 int signalAsu = signalStrength.getAsuLevel(); 368 369 if (-1 == signalDbm) { 370 signalDbm = 0; 371 } 372 373 if (-1 == signalAsu) { 374 signalAsu = 0; 375 } 376 377 mSignalStrength.setSummary(r.getString(R.string.sim_signal_strength, 378 signalDbm, signalAsu)); 379 } 380 } 381 382 private void updatePreference() { 383 if (mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA) { 384 // only show area info when SIM country is Brazil 385 if (COUNTRY_ABBREVIATION_BRAZIL.equals(mTelephonyManager.getSimCountryIso( 386 mSir.getSubscriptionId()))) { 387 mShowLatestAreaInfo = true; 388 } 389 } 390 PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId( 391 mSir.getSubscriptionId()); 392 mShowICCID = carrierConfig.getBoolean( 393 CarrierConfigManager.KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL); 394 395 String rawNumber = mTelephonyManager.getLine1Number(mSir.getSubscriptionId()); 396 String formattedNumber = null; 397 if (!TextUtils.isEmpty(rawNumber)) { 398 formattedNumber = PhoneNumberUtils.formatNumber(rawNumber); 399 } 400 // If formattedNumber is null or empty, it'll display as "Unknown". 401 setSummaryText(KEY_PHONE_NUMBER, formattedNumber); 402 setSummaryText(KEY_IMEI, mPhone.getImei()); 403 setSummaryText(KEY_IMEI_SV, mPhone.getDeviceSvn()); 404 405 if (!mShowICCID) { 406 removePreferenceFromScreen(KEY_ICCID); 407 } else { 408 // Get ICCID, which is SIM serial number 409 String iccid = mTelephonyManager.getSimSerialNumber(mSir.getSubscriptionId()); 410 setSummaryText(KEY_ICCID, iccid); 411 } 412 413 if (!mShowLatestAreaInfo) { 414 removePreferenceFromScreen(KEY_LATEST_AREA_INFO); 415 } 416 } 417 418 private void updatePhoneInfos() { 419 if (mSir != null) { 420 // TODO: http://b/23763013 421 final Phone phone = PhoneFactory.getPhone(SubscriptionManager.getPhoneId( 422 mSir.getSubscriptionId())); 423 if (UserManager.get(getContext()).isAdminUser() 424 && SubscriptionManager.isValidSubscriptionId(mSir.getSubscriptionId())) { 425 if (phone == null) { 426 Log.e(TAG, "Unable to locate a phone object for the given Subscription ID."); 427 return; 428 } 429 430 mPhone = phone; 431 mPhoneStateListener = new PhoneStateListener(mSir.getSubscriptionId()) { 432 @Override 433 public void onDataConnectionStateChanged(int state) { 434 updateDataState(); 435 updateNetworkType(); 436 } 437 438 @Override 439 public void onSignalStrengthsChanged(SignalStrength signalStrength) { 440 updateSignalStrength(signalStrength); 441 } 442 443 @Override 444 public void onServiceStateChanged(ServiceState serviceState) { 445 updateServiceState(serviceState); 446 } 447 }; 448 } 449 } 450 } 451 private OnTabChangeListener mTabListener = new OnTabChangeListener() { 452 @Override 453 public void onTabChanged(String tabId) { 454 final int slotId = Integer.parseInt(tabId); 455 mSir = mSelectableSubInfos.get(slotId); 456 457 // The User has changed tab; update the SIM information. 458 updatePhoneInfos(); 459 mTelephonyManager.listen(mPhoneStateListener, 460 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE 461 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS 462 | PhoneStateListener.LISTEN_SERVICE_STATE); 463 updateDataState(); 464 updateNetworkType(); 465 updatePreference(); 466 } 467 }; 468 469 private TabContentFactory mEmptyTabContent = new TabContentFactory() { 470 @Override 471 public View createTabContent(String tag) { 472 return new View(mTabHost.getContext()); 473 } 474 }; 475 476 private TabSpec buildTabSpec(String tag, String title) { 477 return mTabHost.newTabSpec(tag).setIndicator(title).setContent( 478 mEmptyTabContent); 479 } 480} 481