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.res.Resources;
     24 import android.os.Bundle;
     25 import android.os.ServiceManager;
     26 import android.os.RemoteException;
     27 import android.os.SystemProperties;
     28 import android.os.UserHandle;
     29 import android.preference.Preference;
     30 import android.preference.PreferenceActivity;
     31 import android.telephony.CellBroadcastMessage;
     32 import android.telephony.PhoneNumberUtils;
     33 import android.telephony.PhoneStateListener;
     34 import android.telephony.ServiceState;
     35 import android.telephony.SignalStrength;
     36 import android.telephony.SubscriptionInfo;
     37 import android.telephony.SubscriptionManager;
     38 import android.telephony.TelephonyManager;
     39 import android.provider.Telephony;
     40 import android.text.TextUtils;
     41 import android.util.Log;
     42 
     43 import com.android.internal.telephony.ITelephony;
     44 import com.android.internal.telephony.DefaultPhoneNotifier;
     45 import com.android.internal.telephony.Phone;
     46 import com.android.internal.telephony.PhoneFactory;
     47 import com.android.settings.R;
     48 import com.android.settings.Utils;
     49 
     50 import android.view.View;
     51 import android.widget.ListView;
     52 import android.widget.TabHost;
     53 import android.widget.TabHost.OnTabChangeListener;
     54 import android.widget.TabHost.TabContentFactory;
     55 import android.widget.TabHost.TabSpec;
     56 import android.widget.TabWidget;
     57 
     58 import java.util.ArrayList;
     59 import java.util.List;
     60 
     61 
     62 /**
     63  * Display the following information
     64  * # Phone Number
     65  * # Network
     66  * # Roaming
     67  * # Device Id (IMEI in GSM and MEID in CDMA)
     68  * # Network type
     69  * # Operator info (area info cell broadcast for Brazil)
     70  * # Signal Strength
     71  *
     72  */
     73 public class SimStatus extends PreferenceActivity {
     74     private static final String TAG = "SimStatus";
     75 
     76     private static final String KEY_DATA_STATE = "data_state";
     77     private static final String KEY_SERVICE_STATE = "service_state";
     78     private static final String KEY_OPERATOR_NAME = "operator_name";
     79     private static final String KEY_ROAMING_STATE = "roaming_state";
     80     private static final String KEY_NETWORK_TYPE = "network_type";
     81     private static final String KEY_LATEST_AREA_INFO = "latest_area_info";
     82     private static final String KEY_PHONE_NUMBER = "number";
     83     private static final String KEY_SIGNAL_STRENGTH = "signal_strength";
     84     private static final String KEY_IMEI = "imei";
     85     private static final String KEY_IMEI_SV = "imei_sv";
     86     private static final String COUNTRY_ABBREVIATION_BRAZIL = "br";
     87 
     88     static final String CB_AREA_INFO_RECEIVED_ACTION =
     89             "android.cellbroadcastreceiver.CB_AREA_INFO_RECEIVED";
     90 
     91     static final String GET_LATEST_CB_AREA_INFO_ACTION =
     92             "android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO";
     93 
     94     // Require the sender to have this permission to prevent third-party spoofing.
     95     static final String CB_AREA_INFO_SENDER_PERMISSION =
     96             "android.permission.RECEIVE_EMERGENCY_BROADCAST";
     97 
     98 
     99     private TelephonyManager mTelephonyManager;
    100     private Phone mPhone = null;
    101     private Resources mRes;
    102     private Preference mSignalStrength;
    103     private SubscriptionInfo mSir;
    104     private boolean mShowLatestAreaInfo;
    105 
    106     // Default summary for items
    107     private String mDefaultText;
    108 
    109     private TabHost mTabHost;
    110     private TabWidget mTabWidget;
    111     private ListView mListView;
    112     private List<SubscriptionInfo> mSelectableSubInfos;
    113 
    114     private PhoneStateListener mPhoneStateListener;
    115     private BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() {
    116         @Override
    117         public void onReceive(Context context, Intent intent) {
    118             String action = intent.getAction();
    119             if (CB_AREA_INFO_RECEIVED_ACTION.equals(action)) {
    120                 Bundle extras = intent.getExtras();
    121                 if (extras == null) {
    122                     return;
    123                 }
    124                 CellBroadcastMessage cbMessage = (CellBroadcastMessage) extras.get("message");
    125                 if (cbMessage != null
    126                         && cbMessage.getServiceCategory() == 50
    127                         && mSir.getSubscriptionId() == cbMessage.getSubId()) {
    128                     String latestAreaInfo = cbMessage.getMessageBody();
    129                     updateAreaInfo(latestAreaInfo);
    130                 }
    131             }
    132         }
    133     };
    134 
    135     @Override
    136     protected void onCreate(Bundle icicle) {
    137         super.onCreate(icicle);
    138 
    139         mSelectableSubInfos = new ArrayList<SubscriptionInfo>();
    140         mTelephonyManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
    141 
    142         addPreferencesFromResource(R.xml.device_info_sim_status);
    143 
    144         mRes = getResources();
    145         mDefaultText = mRes.getString(R.string.device_info_default);
    146         // Note - missing in zaku build, be careful later...
    147         mSignalStrength = findPreference(KEY_SIGNAL_STRENGTH);
    148 
    149         for (int i = 0; i < mTelephonyManager.getSimCount(); i++) {
    150             final SubscriptionInfo sir = Utils.findRecordBySlotId(this, i);
    151             if (sir != null) {
    152                 mSelectableSubInfos.add(sir);
    153             }
    154         }
    155 
    156         mSir = mSelectableSubInfos.size() > 0 ? mSelectableSubInfos.get(0) : null;
    157         if (mSelectableSubInfos.size() > 1) {
    158             setContentView(R.layout.sim_information);
    159 
    160             mTabHost = (TabHost) findViewById(android.R.id.tabhost);
    161             mTabWidget = (TabWidget) findViewById(android.R.id.tabs);
    162             mListView = (ListView) findViewById(android.R.id.list);
    163 
    164             mTabHost.setup();
    165             mTabHost.setOnTabChangedListener(mTabListener);
    166             mTabHost.clearAllTabs();
    167 
    168             for (int i = 0; i < mSelectableSubInfos.size(); i++) {
    169                 mTabHost.addTab(buildTabSpec(String.valueOf(i),
    170                         String.valueOf(mSelectableSubInfos.get(i).getDisplayName())));
    171             }
    172         }
    173 
    174         updatePhoneInfos();
    175     }
    176 
    177     @Override
    178     protected void onResume() {
    179         super.onResume();
    180         if (mPhone != null) {
    181             updatePreference();
    182 
    183             updateSignalStrength(mPhone.getSignalStrength());
    184             updateServiceState(mPhone.getServiceState());
    185             updateDataState();
    186             mTelephonyManager.listen(mPhoneStateListener,
    187                     PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
    188                     | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
    189                     | PhoneStateListener.LISTEN_SERVICE_STATE);
    190             if (mShowLatestAreaInfo) {
    191                 registerReceiver(mAreaInfoReceiver, new IntentFilter(CB_AREA_INFO_RECEIVED_ACTION),
    192                         CB_AREA_INFO_SENDER_PERMISSION, null);
    193                 // Ask CellBroadcastReceiver to broadcast the latest area info received
    194                 Intent getLatestIntent = new Intent(GET_LATEST_CB_AREA_INFO_ACTION);
    195                 sendBroadcastAsUser(getLatestIntent, UserHandle.ALL,
    196                         CB_AREA_INFO_SENDER_PERMISSION);
    197             }
    198         }
    199     }
    200 
    201     @Override
    202     public void onPause() {
    203         super.onPause();
    204 
    205         if (mPhone != null) {
    206             mTelephonyManager.listen(mPhoneStateListener,
    207                     PhoneStateListener.LISTEN_NONE);
    208         }
    209         if (mShowLatestAreaInfo) {
    210             unregisterReceiver(mAreaInfoReceiver);
    211         }
    212     }
    213 
    214     /**
    215      * Removes the specified preference, if it exists.
    216      * @param key the key for the Preference item
    217      */
    218     private void removePreferenceFromScreen(String key) {
    219         Preference pref = findPreference(key);
    220         if (pref != null) {
    221             getPreferenceScreen().removePreference(pref);
    222         }
    223     }
    224 
    225     private void setSummaryText(String key, String text) {
    226         if (TextUtils.isEmpty(text)) {
    227             text = mDefaultText;
    228         }
    229         // some preferences may be missing
    230         final Preference preference = findPreference(key);
    231         if (preference != null) {
    232             preference.setSummary(text);
    233         }
    234     }
    235 
    236     private void updateNetworkType() {
    237         // Whether EDGE, UMTS, etc...
    238         String networktype = null;
    239         final int subId = mSir.getSubscriptionId();
    240         final int actualDataNetworkType = mTelephonyManager.getDataNetworkType(
    241                 mSir.getSubscriptionId());
    242         final int actualVoiceNetworkType = mTelephonyManager.getVoiceNetworkType(
    243                 mSir.getSubscriptionId());
    244         if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualDataNetworkType) {
    245             networktype = mTelephonyManager.getNetworkTypeName(actualDataNetworkType);
    246         } else if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualVoiceNetworkType) {
    247             networktype = mTelephonyManager.getNetworkTypeName(actualVoiceNetworkType);
    248         }
    249 
    250         setSummaryText(KEY_NETWORK_TYPE, networktype);
    251     }
    252 
    253     private void updateDataState() {
    254         final int state =
    255                 DefaultPhoneNotifier.convertDataState(mPhone.getDataConnectionState());
    256 
    257         String display = mRes.getString(R.string.radioInfo_unknown);
    258 
    259         switch (state) {
    260             case TelephonyManager.DATA_CONNECTED:
    261                 display = mRes.getString(R.string.radioInfo_data_connected);
    262                 break;
    263             case TelephonyManager.DATA_SUSPENDED:
    264                 display = mRes.getString(R.string.radioInfo_data_suspended);
    265                 break;
    266             case TelephonyManager.DATA_CONNECTING:
    267                 display = mRes.getString(R.string.radioInfo_data_connecting);
    268                 break;
    269             case TelephonyManager.DATA_DISCONNECTED:
    270                 display = mRes.getString(R.string.radioInfo_data_disconnected);
    271                 break;
    272         }
    273 
    274         setSummaryText(KEY_DATA_STATE, display);
    275     }
    276 
    277     private void updateServiceState(ServiceState serviceState) {
    278         final int state = serviceState.getState();
    279         String display = mRes.getString(R.string.radioInfo_unknown);
    280 
    281         switch (state) {
    282             case ServiceState.STATE_IN_SERVICE:
    283                 display = mRes.getString(R.string.radioInfo_service_in);
    284                 break;
    285             case ServiceState.STATE_OUT_OF_SERVICE:
    286             case ServiceState.STATE_EMERGENCY_ONLY:
    287                 display = mRes.getString(R.string.radioInfo_service_out);
    288                 break;
    289             case ServiceState.STATE_POWER_OFF:
    290                 display = mRes.getString(R.string.radioInfo_service_off);
    291                 break;
    292         }
    293 
    294         setSummaryText(KEY_SERVICE_STATE, display);
    295 
    296         if (serviceState.getRoaming()) {
    297             setSummaryText(KEY_ROAMING_STATE, mRes.getString(R.string.radioInfo_roaming_in));
    298         } else {
    299             setSummaryText(KEY_ROAMING_STATE, mRes.getString(R.string.radioInfo_roaming_not));
    300         }
    301         setSummaryText(KEY_OPERATOR_NAME, serviceState.getOperatorAlphaLong());
    302     }
    303 
    304     private void updateAreaInfo(String areaInfo) {
    305         if (areaInfo != null) {
    306             setSummaryText(KEY_LATEST_AREA_INFO, areaInfo);
    307         }
    308     }
    309 
    310     void updateSignalStrength(SignalStrength signalStrength) {
    311         if (mSignalStrength != null) {
    312             final int state = mPhone.getServiceState().getState();
    313             Resources r = getResources();
    314 
    315             if ((ServiceState.STATE_OUT_OF_SERVICE == state) ||
    316                     (ServiceState.STATE_POWER_OFF == state)) {
    317                 mSignalStrength.setSummary("0");
    318             }
    319 
    320             int signalDbm = signalStrength.getDbm();
    321             int signalAsu = signalStrength.getAsuLevel();
    322 
    323             if (-1 == signalDbm) {
    324                 signalDbm = 0;
    325             }
    326 
    327             if (-1 == signalAsu) {
    328                 signalAsu = 0;
    329             }
    330 
    331             mSignalStrength.setSummary(r.getString(R.string.sim_signal_strength,
    332                         signalDbm, signalAsu));
    333         }
    334     }
    335 
    336     private void updatePreference() {
    337         if (mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA) {
    338             // only show area info when SIM country is Brazil
    339             if (COUNTRY_ABBREVIATION_BRAZIL.equals(mTelephonyManager.getSimCountryIso(
    340                             mSir.getSubscriptionId()))) {
    341                 mShowLatestAreaInfo = true;
    342             }
    343         }
    344 
    345         String rawNumber = mTelephonyManager.getLine1NumberForSubscriber(mSir.getSubscriptionId());
    346         String formattedNumber = null;
    347         if (!TextUtils.isEmpty(rawNumber)) {
    348             formattedNumber = PhoneNumberUtils.formatNumber(rawNumber);
    349         }
    350         // If formattedNumber is null or empty, it'll display as "Unknown".
    351         setSummaryText(KEY_PHONE_NUMBER, formattedNumber);
    352         final String imei = mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA
    353                 ? mPhone.getImei() : mPhone.getDeviceId();
    354         setSummaryText(KEY_IMEI, imei);
    355         setSummaryText(KEY_IMEI_SV, mTelephonyManager.getDeviceSoftwareVersion(/*slotId*/));
    356 
    357         if (!mShowLatestAreaInfo) {
    358             removePreferenceFromScreen(KEY_LATEST_AREA_INFO);
    359         }
    360     }
    361 
    362     private void updatePhoneInfos() {
    363         if (mSir != null) {
    364             final Phone phone = PhoneFactory.getPhone(SubscriptionManager.getPhoneId(
    365                         mSir.getSubscriptionId()));
    366             if (UserHandle.myUserId() == UserHandle.USER_OWNER
    367                     && SubscriptionManager.isValidSubscriptionId(mSir.getSubscriptionId())) {
    368                 if (phone == null) {
    369                     Log.e(TAG, "Unable to locate a phone object for the given Subscription ID.");
    370                     return;
    371                 }
    372 
    373                 mPhone = phone;
    374                 mPhoneStateListener = new PhoneStateListener(mSir.getSubscriptionId()) {
    375                     @Override
    376                     public void onDataConnectionStateChanged(int state) {
    377                         updateDataState();
    378                         updateNetworkType();
    379                     }
    380 
    381                     @Override
    382                     public void onSignalStrengthsChanged(SignalStrength signalStrength) {
    383                         updateSignalStrength(signalStrength);
    384                     }
    385 
    386                     @Override
    387                     public void onServiceStateChanged(ServiceState serviceState) {
    388                         updateServiceState(serviceState);
    389                     }
    390                 };
    391             }
    392         }
    393     }
    394     private OnTabChangeListener mTabListener = new OnTabChangeListener() {
    395         @Override
    396         public void onTabChanged(String tabId) {
    397             final int slotId = Integer.parseInt(tabId);
    398             mSir = mSelectableSubInfos.get(slotId);
    399 
    400             // The User has changed tab; update the SIM information.
    401             updatePhoneInfos();
    402             mTelephonyManager.listen(mPhoneStateListener,
    403                     PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
    404                     | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
    405                     | PhoneStateListener.LISTEN_SERVICE_STATE);
    406             updateDataState();
    407             updateNetworkType();
    408             updatePreference();
    409         }
    410     };
    411 
    412     private TabContentFactory mEmptyTabContent = new TabContentFactory() {
    413         @Override
    414         public View createTabContent(String tag) {
    415             return new View(mTabHost.getContext());
    416         }
    417     };
    418 
    419     private TabSpec buildTabSpec(String tag, String title) {
    420         return mTabHost.newTabSpec(tag).setIndicator(title).setContent(
    421                 mEmptyTabContent);
    422     }
    423 }
    424