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 { onConnectivityStateChanged(final Context context, final Intent intent)42 public void onConnectivityStateChanged(final Context context, final Intent intent); onPhoneStateChanged(final Context context, int serviceState)43 public void onPhoneStateChanged(final Context context, int serviceState); 44 } 45 ConnectivityUtil(final Context context)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 getCurrentServiceState()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 onPhoneStateChanged(final int serviceState)75 private void onPhoneStateChanged(final int serviceState) { 76 final ConnectivityListener listener = mListener; 77 if (listener != null) { 78 listener.onPhoneStateChanged(mContext, serviceState); 79 } 80 } 81 onConnectivityChanged(final Context context, final Intent intent)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 register(final ConnectivityListener listener)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 unregister()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 onReceive(final Context context, final Intent intent)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 registerForSignalStrength()145 public void registerForSignalStrength() { 146 mTelephonyManager.listen( 147 mSignalStrengthListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); 148 } 149 unregisterForSignalStrength()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 */ getSignalLevel(final int subId)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 getLevel(final SignalStrength signalStrength)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 */ getCdmaLevel(final SignalStrength signalStrength)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 */ getEvdoLevel(final SignalStrength signalStrength)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