Home | History | Annotate | Download | only in deviceinfo
      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 android.content.BroadcastReceiver;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.IntentFilter;
     23 import android.content.pm.PackageManager.NameNotFoundException;
     24 import android.content.res.Resources;
     25 import android.os.Bundle;
     26 import android.os.PersistableBundle;
     27 import android.os.UserHandle;
     28 import android.os.UserManager;
     29 import android.support.v7.preference.Preference;
     30 import android.telephony.CarrierConfigManager;
     31 import android.telephony.CellBroadcastMessage;
     32 import android.telephony.PhoneStateListener;
     33 import android.telephony.ServiceState;
     34 import android.telephony.SignalStrength;
     35 import android.telephony.SubscriptionInfo;
     36 import android.telephony.SubscriptionManager;
     37 import android.telephony.TelephonyManager;
     38 import android.text.TextUtils;
     39 import android.util.Log;
     40 import android.view.LayoutInflater;
     41 import android.view.View;
     42 import android.view.ViewGroup;
     43 import android.widget.ListView;
     44 import android.widget.TabHost;
     45 import android.widget.TabHost.OnTabChangeListener;
     46 import android.widget.TabHost.TabContentFactory;
     47 import android.widget.TabHost.TabSpec;
     48 import android.widget.TabWidget;
     49 
     50 import com.android.internal.logging.MetricsProto.MetricsEvent;
     51 import com.android.internal.telephony.DefaultPhoneNotifier;
     52 import com.android.internal.telephony.Phone;
     53 import com.android.internal.telephony.PhoneFactory;
     54 import com.android.settings.R;
     55 import com.android.settings.SettingsPreferenceFragment;
     56 import com.android.settings.Utils;
     57 import com.android.settingslib.DeviceInfoUtils;
     58 
     59 import java.util.List;
     60 
     61 import static android.content.Context.CARRIER_CONFIG_SERVICE;
     62 import 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  */
     76 public 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