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