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 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