Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2015 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.messaging.util;
     18 
     19 import android.content.BroadcastReceiver;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.IntentFilter;
     23 import android.net.ConnectivityManager;
     24 import android.telephony.PhoneStateListener;
     25 import android.telephony.ServiceState;
     26 import android.telephony.SignalStrength;
     27 import android.telephony.TelephonyManager;
     28 
     29 public class ConnectivityUtil {
     30     // Assume not connected until informed differently
     31     private volatile int mCurrentServiceState = ServiceState.STATE_POWER_OFF;
     32 
     33     private final TelephonyManager mTelephonyManager;
     34     private final Context mContext;
     35     private final ConnectivityBroadcastReceiver mReceiver;
     36     private final ConnectivityManager mConnMgr;
     37 
     38     private ConnectivityListener mListener;
     39     private final IntentFilter mIntentFilter;
     40 
     41     public interface ConnectivityListener {
     42         public void onConnectivityStateChanged(final Context context, final Intent intent);
     43         public void onPhoneStateChanged(final Context context, int serviceState);
     44     }
     45 
     46     public ConnectivityUtil(final Context context) {
     47         mContext = context;
     48         mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
     49         mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
     50         mReceiver = new ConnectivityBroadcastReceiver();
     51         mIntentFilter = new IntentFilter();
     52         mIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
     53     }
     54 
     55     public int getCurrentServiceState() {
     56         return mCurrentServiceState;
     57     }
     58 
     59     private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
     60         @Override
     61         public void onServiceStateChanged(final ServiceState serviceState) {
     62             if (mCurrentServiceState != serviceState.getState()) {
     63                 mCurrentServiceState = serviceState.getState();
     64                 onPhoneStateChanged(mCurrentServiceState);
     65             }
     66         }
     67 
     68         @Override
     69         public void onDataConnectionStateChanged(final int state) {
     70             mCurrentServiceState = (state == TelephonyManager.DATA_DISCONNECTED) ?
     71                     ServiceState.STATE_OUT_OF_SERVICE : ServiceState.STATE_IN_SERVICE;
     72         }
     73     };
     74 
     75     private void onPhoneStateChanged(final int serviceState) {
     76         final ConnectivityListener listener = mListener;
     77         if (listener != null) {
     78             listener.onPhoneStateChanged(mContext, serviceState);
     79         }
     80     }
     81 
     82     private void onConnectivityChanged(final Context context, final Intent intent) {
     83         final ConnectivityListener listener = mListener;
     84         if (listener != null) {
     85             listener.onConnectivityStateChanged(context, intent);
     86         }
     87     }
     88 
     89     public void register(final ConnectivityListener listener) {
     90         Assert.isTrue(mListener == null || mListener == listener);
     91         if (mListener == null) {
     92             if (mTelephonyManager != null) {
     93                 mCurrentServiceState = (PhoneUtils.getDefault().isAirplaneModeOn() ?
     94                         ServiceState.STATE_POWER_OFF : ServiceState.STATE_IN_SERVICE);
     95                 mTelephonyManager.listen(mPhoneStateListener,
     96                         PhoneStateListener.LISTEN_SERVICE_STATE);
     97             }
     98             if (mConnMgr != null) {
     99                 mContext.registerReceiver(mReceiver, mIntentFilter);
    100             }
    101         }
    102         mListener = listener;
    103     }
    104 
    105     public void unregister() {
    106         if (mListener != null) {
    107             if (mTelephonyManager != null) {
    108                 mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
    109                 mCurrentServiceState = ServiceState.STATE_POWER_OFF;
    110             }
    111             if (mConnMgr != null) {
    112                 mContext.unregisterReceiver(mReceiver);
    113             }
    114         }
    115         mListener = null;
    116     }
    117 
    118     /**
    119      * Connectivity change broadcast receiver. This gets the network connectivity updates.
    120      * In case we don't get the active connectivity when we first acquire the network,
    121      * this receiver will notify us when it is connected, so to unblock the waiting thread
    122      * which is sending the message.
    123      */
    124     public class ConnectivityBroadcastReceiver extends BroadcastReceiver {
    125         @Override
    126         public void onReceive(final Context context, final Intent intent) {
    127             if (!intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
    128                 return;
    129             }
    130 
    131             onConnectivityChanged(context, intent);
    132         }
    133     }
    134 
    135     private int mSignalLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
    136 
    137     // We use a separate instance than mPhoneStateListener because the lifetimes are different.
    138     private final PhoneStateListener mSignalStrengthListener = new PhoneStateListener() {
    139         @Override
    140         public void onSignalStrengthsChanged(final SignalStrength signalStrength) {
    141             mSignalLevel = getLevel(signalStrength);
    142         }
    143     };
    144 
    145     public void registerForSignalStrength() {
    146         mTelephonyManager.listen(
    147                 mSignalStrengthListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
    148     }
    149 
    150     public void unregisterForSignalStrength() {
    151         mTelephonyManager.listen(mSignalStrengthListener, PhoneStateListener.LISTEN_NONE);
    152     }
    153 
    154     /**
    155      * @param subId This is ignored because TelephonyManager does not support it.
    156      * @return Signal strength as level 0..4
    157      */
    158     public int getSignalLevel(final int subId) {
    159         return mSignalLevel;
    160     }
    161 
    162     private static final int SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
    163     private static final int SIGNAL_STRENGTH_POOR = 1;
    164     private static final int SIGNAL_STRENGTH_MODERATE = 2;
    165     private static final int SIGNAL_STRENGTH_GOOD = 3;
    166     private static final int SIGNAL_STRENGTH_GREAT = 4;
    167 
    168     private static final int GSM_SIGNAL_STRENGTH_GREAT = 12;
    169     private static final int GSM_SIGNAL_STRENGTH_GOOD = 8;
    170     private static final int GSM_SIGNAL_STRENGTH_MODERATE = 8;
    171 
    172     private static int getLevel(final SignalStrength signalStrength) {
    173         if (signalStrength.isGsm()) {
    174             // From frameworks/base/telephony/java/android/telephony/CellSignalStrengthGsm.java
    175 
    176             // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
    177             // asu = 0 (-113dB or less) is very weak
    178             // signal, its better to show 0 bars to the user in such cases.
    179             // asu = 99 is a special case, where the signal strength is unknown.
    180             final int asu = signalStrength.getGsmSignalStrength();
    181             if (asu <= 2 || asu == 99) return SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
    182             else if (asu >= GSM_SIGNAL_STRENGTH_GREAT) return SIGNAL_STRENGTH_GREAT;
    183             else if (asu >= GSM_SIGNAL_STRENGTH_GOOD) return SIGNAL_STRENGTH_GOOD;
    184             else if (asu >= GSM_SIGNAL_STRENGTH_MODERATE) return SIGNAL_STRENGTH_MODERATE;
    185             else return SIGNAL_STRENGTH_POOR;
    186         } else {
    187             // From frameworks/base/telephony/java/android/telephony/CellSignalStrengthCdma.java
    188 
    189             final int cdmaLevel = getCdmaLevel(signalStrength);
    190             final int evdoLevel = getEvdoLevel(signalStrength);
    191             if (evdoLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
    192                 /* We don't know evdo, use cdma */
    193                 return getCdmaLevel(signalStrength);
    194             } else if (cdmaLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
    195                 /* We don't know cdma, use evdo */
    196                 return getEvdoLevel(signalStrength);
    197             } else {
    198                 /* We know both, use the lowest level */
    199                 return cdmaLevel < evdoLevel ? cdmaLevel : evdoLevel;
    200             }
    201         }
    202     }
    203 
    204     /**
    205      * Get cdma as level 0..4
    206      */
    207     private static int getCdmaLevel(final SignalStrength signalStrength) {
    208         final int cdmaDbm = signalStrength.getCdmaDbm();
    209         final int cdmaEcio = signalStrength.getCdmaEcio();
    210         int levelDbm;
    211         int levelEcio;
    212         if (cdmaDbm >= -75) levelDbm = SIGNAL_STRENGTH_GREAT;
    213         else if (cdmaDbm >= -85) levelDbm = SIGNAL_STRENGTH_GOOD;
    214         else if (cdmaDbm >= -95) levelDbm = SIGNAL_STRENGTH_MODERATE;
    215         else if (cdmaDbm >= -100) levelDbm = SIGNAL_STRENGTH_POOR;
    216         else levelDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
    217         // Ec/Io are in dB*10
    218         if (cdmaEcio >= -90) levelEcio = SIGNAL_STRENGTH_GREAT;
    219         else if (cdmaEcio >= -110) levelEcio = SIGNAL_STRENGTH_GOOD;
    220         else if (cdmaEcio >= -130) levelEcio = SIGNAL_STRENGTH_MODERATE;
    221         else if (cdmaEcio >= -150) levelEcio = SIGNAL_STRENGTH_POOR;
    222         else levelEcio = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
    223         final int level = (levelDbm < levelEcio) ? levelDbm : levelEcio;
    224         return level;
    225     }
    226     /**
    227      * Get Evdo as level 0..4
    228      */
    229     private static int getEvdoLevel(final SignalStrength signalStrength) {
    230         final int evdoDbm = signalStrength.getEvdoDbm();
    231         final int evdoSnr = signalStrength.getEvdoSnr();
    232         int levelEvdoDbm;
    233         int levelEvdoSnr;
    234         if (evdoDbm >= -65) levelEvdoDbm = SIGNAL_STRENGTH_GREAT;
    235         else if (evdoDbm >= -75) levelEvdoDbm = SIGNAL_STRENGTH_GOOD;
    236         else if (evdoDbm >= -90) levelEvdoDbm = SIGNAL_STRENGTH_MODERATE;
    237         else if (evdoDbm >= -105) levelEvdoDbm = SIGNAL_STRENGTH_POOR;
    238         else levelEvdoDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
    239         if (evdoSnr >= 7) levelEvdoSnr = SIGNAL_STRENGTH_GREAT;
    240         else if (evdoSnr >= 5) levelEvdoSnr = SIGNAL_STRENGTH_GOOD;
    241         else if (evdoSnr >= 3) levelEvdoSnr = SIGNAL_STRENGTH_MODERATE;
    242         else if (evdoSnr >= 1) levelEvdoSnr = SIGNAL_STRENGTH_POOR;
    243         else levelEvdoSnr = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
    244         final int level = (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
    245         return level;
    246     }
    247 }
    248