| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.settings.deviceinfo; |
| |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.content.pm.PackageManager.NameNotFoundException; |
| import android.content.res.Resources; |
| import android.os.Bundle; |
| import android.os.UserHandle; |
| import android.os.UserManager; |
| import android.support.v7.preference.Preference; |
| import android.telephony.CellBroadcastMessage; |
| import android.telephony.PhoneNumberUtils; |
| import android.telephony.PhoneStateListener; |
| import android.telephony.ServiceState; |
| import android.telephony.SignalStrength; |
| import android.telephony.SubscriptionInfo; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.TelephonyManager; |
| import android.text.TextUtils; |
| import android.util.Log; |
| import android.view.View; |
| import android.widget.ListView; |
| import android.widget.TabHost; |
| import android.widget.TabHost.OnTabChangeListener; |
| import android.widget.TabHost.TabContentFactory; |
| import android.widget.TabHost.TabSpec; |
| import android.widget.TabWidget; |
| |
| import com.android.internal.logging.MetricsLogger; |
| import com.android.internal.telephony.DefaultPhoneNotifier; |
| import com.android.internal.telephony.Phone; |
| import com.android.internal.telephony.PhoneFactory; |
| import com.android.settings.InstrumentedPreferenceActivity; |
| import com.android.settings.R; |
| |
| import java.util.List; |
| |
| |
| /** |
| * Display the following information |
| * # Phone Number |
| * # Network |
| * # Roaming |
| * # Device Id (IMEI in GSM and MEID in CDMA) |
| * # Network type |
| * # Operator info (area info cell broadcast for Brazil) |
| * # Signal Strength |
| * |
| */ |
| public class SimStatus extends InstrumentedPreferenceActivity { |
| private static final String TAG = "SimStatus"; |
| |
| private static final String KEY_DATA_STATE = "data_state"; |
| private static final String KEY_SERVICE_STATE = "service_state"; |
| private static final String KEY_OPERATOR_NAME = "operator_name"; |
| private static final String KEY_ROAMING_STATE = "roaming_state"; |
| private static final String KEY_NETWORK_TYPE = "network_type"; |
| private static final String KEY_LATEST_AREA_INFO = "latest_area_info"; |
| private static final String KEY_PHONE_NUMBER = "number"; |
| private static final String KEY_SIGNAL_STRENGTH = "signal_strength"; |
| private static final String KEY_IMEI = "imei"; |
| private static final String KEY_IMEI_SV = "imei_sv"; |
| private static final String COUNTRY_ABBREVIATION_BRAZIL = "br"; |
| |
| static final String CB_AREA_INFO_RECEIVED_ACTION = |
| "android.cellbroadcastreceiver.CB_AREA_INFO_RECEIVED"; |
| |
| static final String GET_LATEST_CB_AREA_INFO_ACTION = |
| "android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO"; |
| |
| // Require the sender to have this permission to prevent third-party spoofing. |
| static final String CB_AREA_INFO_SENDER_PERMISSION = |
| "android.permission.RECEIVE_EMERGENCY_BROADCAST"; |
| |
| |
| private TelephonyManager mTelephonyManager; |
| private Phone mPhone = null; |
| private Resources mRes; |
| private Preference mSignalStrength; |
| private SubscriptionInfo mSir; |
| private boolean mShowLatestAreaInfo; |
| |
| // Default summary for items |
| private String mDefaultText; |
| |
| private TabHost mTabHost; |
| private TabWidget mTabWidget; |
| private ListView mListView; |
| private List<SubscriptionInfo> mSelectableSubInfos; |
| |
| private PhoneStateListener mPhoneStateListener; |
| private BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| String action = intent.getAction(); |
| if (CB_AREA_INFO_RECEIVED_ACTION.equals(action)) { |
| Bundle extras = intent.getExtras(); |
| if (extras == null) { |
| return; |
| } |
| CellBroadcastMessage cbMessage = (CellBroadcastMessage) extras.get("message"); |
| if (cbMessage != null |
| && cbMessage.getServiceCategory() == 50 |
| && mSir.getSubscriptionId() == cbMessage.getSubId()) { |
| String latestAreaInfo = cbMessage.getMessageBody(); |
| updateAreaInfo(latestAreaInfo); |
| } |
| } |
| } |
| }; |
| |
| @Override |
| protected void onCreate(Bundle icicle) { |
| super.onCreate(icicle); |
| mTelephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); |
| |
| mSelectableSubInfos = SubscriptionManager.from(this).getActiveSubscriptionInfoList(); |
| |
| addPreferencesFromResource(R.xml.device_info_sim_status); |
| |
| mRes = getResources(); |
| mDefaultText = mRes.getString(R.string.device_info_default); |
| // Note - missing in zaku build, be careful later... |
| mSignalStrength = findPreference(KEY_SIGNAL_STRENGTH); |
| |
| if (mSelectableSubInfos == null) { |
| mSir = null; |
| } else { |
| mSir = mSelectableSubInfos.size() > 0 ? mSelectableSubInfos.get(0) : null; |
| |
| if (mSelectableSubInfos.size() > 1) { |
| setContentView(com.android.internal.R.layout.common_tab_settings); |
| |
| mTabHost = (TabHost) findViewById(android.R.id.tabhost); |
| mTabWidget = (TabWidget) findViewById(android.R.id.tabs); |
| mListView = (ListView) findViewById(android.R.id.list); |
| |
| mTabHost.setup(); |
| mTabHost.setOnTabChangedListener(mTabListener); |
| mTabHost.clearAllTabs(); |
| |
| for (int i = 0; i < mSelectableSubInfos.size(); i++) { |
| mTabHost.addTab(buildTabSpec(String.valueOf(i), |
| String.valueOf(mSelectableSubInfos.get(i).getDisplayName()))); |
| } |
| } |
| } |
| updatePhoneInfos(); |
| } |
| |
| @Override |
| protected int getMetricsCategory() { |
| return MetricsLogger.DEVICEINFO_SIM_STATUS; |
| } |
| |
| @Override |
| protected void onResume() { |
| super.onResume(); |
| if (mPhone != null) { |
| updatePreference(); |
| |
| updateSignalStrength(mPhone.getSignalStrength()); |
| updateServiceState(mPhone.getServiceState()); |
| updateDataState(); |
| mTelephonyManager.listen(mPhoneStateListener, |
| PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
| | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS |
| | PhoneStateListener.LISTEN_SERVICE_STATE); |
| if (mShowLatestAreaInfo) { |
| registerReceiver(mAreaInfoReceiver, new IntentFilter(CB_AREA_INFO_RECEIVED_ACTION), |
| CB_AREA_INFO_SENDER_PERMISSION, null); |
| // Ask CellBroadcastReceiver to broadcast the latest area info received |
| Intent getLatestIntent = new Intent(GET_LATEST_CB_AREA_INFO_ACTION); |
| sendBroadcastAsUser(getLatestIntent, UserHandle.ALL, |
| CB_AREA_INFO_SENDER_PERMISSION); |
| } |
| } |
| } |
| |
| @Override |
| public void onPause() { |
| super.onPause(); |
| |
| if (mPhone != null) { |
| mTelephonyManager.listen(mPhoneStateListener, |
| PhoneStateListener.LISTEN_NONE); |
| } |
| if (mShowLatestAreaInfo) { |
| unregisterReceiver(mAreaInfoReceiver); |
| } |
| } |
| |
| /** |
| * Removes the specified preference, if it exists. |
| * @param key the key for the Preference item |
| */ |
| private void removePreferenceFromScreen(String key) { |
| Preference pref = findPreference(key); |
| if (pref != null) { |
| getPreferenceScreen().removePreference(pref); |
| } |
| } |
| |
| private void setSummaryText(String key, String text) { |
| if (TextUtils.isEmpty(text)) { |
| text = mDefaultText; |
| } |
| // some preferences may be missing |
| final Preference preference = findPreference(key); |
| if (preference != null) { |
| preference.setSummary(text); |
| } |
| } |
| |
| private void updateNetworkType() { |
| // Whether EDGE, UMTS, etc... |
| String networktype = null; |
| final int subId = mSir.getSubscriptionId(); |
| final int actualDataNetworkType = mTelephonyManager.getDataNetworkType( |
| mSir.getSubscriptionId()); |
| final int actualVoiceNetworkType = mTelephonyManager.getVoiceNetworkType( |
| mSir.getSubscriptionId()); |
| if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualDataNetworkType) { |
| networktype = mTelephonyManager.getNetworkTypeName(actualDataNetworkType); |
| } else if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualVoiceNetworkType) { |
| networktype = mTelephonyManager.getNetworkTypeName(actualVoiceNetworkType); |
| } |
| |
| boolean show4GForLTE = false; |
| try { |
| Context con = createPackageContext("com.android.systemui", 0); |
| int id = con.getResources().getIdentifier("config_show4GForLTE", |
| "bool", "com.android.systemui"); |
| show4GForLTE = con.getResources().getBoolean(id); |
| } catch (NameNotFoundException e) { |
| Log.e(TAG, "NameNotFoundException for show4GFotLTE"); |
| } |
| |
| if (networktype != null && networktype.equals("LTE") && show4GForLTE) { |
| networktype = "4G"; |
| } |
| setSummaryText(KEY_NETWORK_TYPE, networktype); |
| } |
| |
| private void updateDataState() { |
| final int state = |
| DefaultPhoneNotifier.convertDataState(mPhone.getDataConnectionState()); |
| |
| String display = mRes.getString(R.string.radioInfo_unknown); |
| |
| switch (state) { |
| case TelephonyManager.DATA_CONNECTED: |
| display = mRes.getString(R.string.radioInfo_data_connected); |
| break; |
| case TelephonyManager.DATA_SUSPENDED: |
| display = mRes.getString(R.string.radioInfo_data_suspended); |
| break; |
| case TelephonyManager.DATA_CONNECTING: |
| display = mRes.getString(R.string.radioInfo_data_connecting); |
| break; |
| case TelephonyManager.DATA_DISCONNECTED: |
| display = mRes.getString(R.string.radioInfo_data_disconnected); |
| break; |
| } |
| |
| setSummaryText(KEY_DATA_STATE, display); |
| } |
| |
| private void updateServiceState(ServiceState serviceState) { |
| final int state = serviceState.getState(); |
| String display = mRes.getString(R.string.radioInfo_unknown); |
| |
| switch (state) { |
| case ServiceState.STATE_IN_SERVICE: |
| display = mRes.getString(R.string.radioInfo_service_in); |
| break; |
| case ServiceState.STATE_OUT_OF_SERVICE: |
| // Set signal strength to 0 when service state is STATE_OUT_OF_SERVICE |
| mSignalStrength.setSummary("0"); |
| case ServiceState.STATE_EMERGENCY_ONLY: |
| // Set summary string of service state to radioInfo_service_out when |
| // service state is both STATE_OUT_OF_SERVICE & STATE_EMERGENCY_ONLY |
| display = mRes.getString(R.string.radioInfo_service_out); |
| break; |
| case ServiceState.STATE_POWER_OFF: |
| display = mRes.getString(R.string.radioInfo_service_off); |
| // Also set signal strength to 0 |
| mSignalStrength.setSummary("0"); |
| break; |
| } |
| |
| setSummaryText(KEY_SERVICE_STATE, display); |
| |
| if (serviceState.getRoaming()) { |
| setSummaryText(KEY_ROAMING_STATE, mRes.getString(R.string.radioInfo_roaming_in)); |
| } else { |
| setSummaryText(KEY_ROAMING_STATE, mRes.getString(R.string.radioInfo_roaming_not)); |
| } |
| setSummaryText(KEY_OPERATOR_NAME, serviceState.getOperatorAlphaLong()); |
| } |
| |
| private void updateAreaInfo(String areaInfo) { |
| if (areaInfo != null) { |
| setSummaryText(KEY_LATEST_AREA_INFO, areaInfo); |
| } |
| } |
| |
| void updateSignalStrength(SignalStrength signalStrength) { |
| if (mSignalStrength != null) { |
| final int state = mPhone.getServiceState().getState(); |
| Resources r = getResources(); |
| |
| if ((ServiceState.STATE_OUT_OF_SERVICE == state) || |
| (ServiceState.STATE_POWER_OFF == state)) { |
| mSignalStrength.setSummary("0"); |
| return; |
| } |
| |
| int signalDbm = signalStrength.getDbm(); |
| int signalAsu = signalStrength.getAsuLevel(); |
| |
| if (-1 == signalDbm) { |
| signalDbm = 0; |
| } |
| |
| if (-1 == signalAsu) { |
| signalAsu = 0; |
| } |
| |
| mSignalStrength.setSummary(r.getString(R.string.sim_signal_strength, |
| signalDbm, signalAsu)); |
| } |
| } |
| |
| private void updatePreference() { |
| if (mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA) { |
| // only show area info when SIM country is Brazil |
| if (COUNTRY_ABBREVIATION_BRAZIL.equals(mTelephonyManager.getSimCountryIso( |
| mSir.getSubscriptionId()))) { |
| mShowLatestAreaInfo = true; |
| } |
| } |
| |
| String rawNumber = mTelephonyManager.getLine1NumberForSubscriber(mSir.getSubscriptionId()); |
| String formattedNumber = null; |
| if (!TextUtils.isEmpty(rawNumber)) { |
| formattedNumber = PhoneNumberUtils.formatNumber(rawNumber); |
| } |
| // If formattedNumber is null or empty, it'll display as "Unknown". |
| setSummaryText(KEY_PHONE_NUMBER, formattedNumber); |
| setSummaryText(KEY_IMEI, mPhone.getImei()); |
| setSummaryText(KEY_IMEI_SV, mPhone.getDeviceSvn()); |
| |
| if (!mShowLatestAreaInfo) { |
| removePreferenceFromScreen(KEY_LATEST_AREA_INFO); |
| } |
| } |
| |
| private void updatePhoneInfos() { |
| if (mSir != null) { |
| // TODO: http://b/23763013 |
| final Phone phone = PhoneFactory.getPhone(SubscriptionManager.getPhoneId( |
| mSir.getSubscriptionId())); |
| if (UserManager.get(this).isAdminUser() |
| && SubscriptionManager.isValidSubscriptionId(mSir.getSubscriptionId())) { |
| if (phone == null) { |
| Log.e(TAG, "Unable to locate a phone object for the given Subscription ID."); |
| return; |
| } |
| |
| mPhone = phone; |
| mPhoneStateListener = new PhoneStateListener(mSir.getSubscriptionId()) { |
| @Override |
| public void onDataConnectionStateChanged(int state) { |
| updateDataState(); |
| updateNetworkType(); |
| } |
| |
| @Override |
| public void onSignalStrengthsChanged(SignalStrength signalStrength) { |
| updateSignalStrength(signalStrength); |
| } |
| |
| @Override |
| public void onServiceStateChanged(ServiceState serviceState) { |
| updateServiceState(serviceState); |
| } |
| }; |
| } |
| } |
| } |
| private OnTabChangeListener mTabListener = new OnTabChangeListener() { |
| @Override |
| public void onTabChanged(String tabId) { |
| final int slotId = Integer.parseInt(tabId); |
| mSir = mSelectableSubInfos.get(slotId); |
| |
| // The User has changed tab; update the SIM information. |
| updatePhoneInfos(); |
| mTelephonyManager.listen(mPhoneStateListener, |
| PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
| | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS |
| | PhoneStateListener.LISTEN_SERVICE_STATE); |
| updateDataState(); |
| updateNetworkType(); |
| updatePreference(); |
| } |
| }; |
| |
| private TabContentFactory mEmptyTabContent = new TabContentFactory() { |
| @Override |
| public View createTabContent(String tag) { |
| return new View(mTabHost.getContext()); |
| } |
| }; |
| |
| private TabSpec buildTabSpec(String tag, String title) { |
| return mTabHost.newTabSpec(tag).setIndicator(title).setContent( |
| mEmptyTabContent); |
| } |
| } |