| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.messaging.util; |
| |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.net.ConnectivityManager; |
| import android.telephony.PhoneStateListener; |
| import android.telephony.ServiceState; |
| import android.telephony.SignalStrength; |
| import android.telephony.TelephonyManager; |
| |
| public class ConnectivityUtil { |
| // Assume not connected until informed differently |
| private volatile int mCurrentServiceState = ServiceState.STATE_POWER_OFF; |
| |
| private final TelephonyManager mTelephonyManager; |
| private final Context mContext; |
| private final ConnectivityBroadcastReceiver mReceiver; |
| private final ConnectivityManager mConnMgr; |
| |
| private ConnectivityListener mListener; |
| private final IntentFilter mIntentFilter; |
| |
| public interface ConnectivityListener { |
| public void onConnectivityStateChanged(final Context context, final Intent intent); |
| public void onPhoneStateChanged(final Context context, int serviceState); |
| } |
| |
| public ConnectivityUtil(final Context context) { |
| mContext = context; |
| mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); |
| mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
| mReceiver = new ConnectivityBroadcastReceiver(); |
| mIntentFilter = new IntentFilter(); |
| mIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); |
| } |
| |
| public int getCurrentServiceState() { |
| return mCurrentServiceState; |
| } |
| |
| private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { |
| @Override |
| public void onServiceStateChanged(final ServiceState serviceState) { |
| if (mCurrentServiceState != serviceState.getState()) { |
| mCurrentServiceState = serviceState.getState(); |
| onPhoneStateChanged(mCurrentServiceState); |
| } |
| } |
| |
| @Override |
| public void onDataConnectionStateChanged(final int state) { |
| mCurrentServiceState = (state == TelephonyManager.DATA_DISCONNECTED) ? |
| ServiceState.STATE_OUT_OF_SERVICE : ServiceState.STATE_IN_SERVICE; |
| } |
| }; |
| |
| private void onPhoneStateChanged(final int serviceState) { |
| final ConnectivityListener listener = mListener; |
| if (listener != null) { |
| listener.onPhoneStateChanged(mContext, serviceState); |
| } |
| } |
| |
| private void onConnectivityChanged(final Context context, final Intent intent) { |
| final ConnectivityListener listener = mListener; |
| if (listener != null) { |
| listener.onConnectivityStateChanged(context, intent); |
| } |
| } |
| |
| public void register(final ConnectivityListener listener) { |
| Assert.isTrue(mListener == null || mListener == listener); |
| if (mListener == null) { |
| if (mTelephonyManager != null) { |
| mCurrentServiceState = (PhoneUtils.getDefault().isAirplaneModeOn() ? |
| ServiceState.STATE_POWER_OFF : ServiceState.STATE_IN_SERVICE); |
| mTelephonyManager.listen(mPhoneStateListener, |
| PhoneStateListener.LISTEN_SERVICE_STATE); |
| } |
| if (mConnMgr != null) { |
| mContext.registerReceiver(mReceiver, mIntentFilter); |
| } |
| } |
| mListener = listener; |
| } |
| |
| public void unregister() { |
| if (mListener != null) { |
| if (mTelephonyManager != null) { |
| mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); |
| mCurrentServiceState = ServiceState.STATE_POWER_OFF; |
| } |
| if (mConnMgr != null) { |
| mContext.unregisterReceiver(mReceiver); |
| } |
| } |
| mListener = null; |
| } |
| |
| /** |
| * Connectivity change broadcast receiver. This gets the network connectivity updates. |
| * In case we don't get the active connectivity when we first acquire the network, |
| * this receiver will notify us when it is connected, so to unblock the waiting thread |
| * which is sending the message. |
| */ |
| public class ConnectivityBroadcastReceiver extends BroadcastReceiver { |
| @Override |
| public void onReceive(final Context context, final Intent intent) { |
| if (!intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { |
| return; |
| } |
| |
| onConnectivityChanged(context, intent); |
| } |
| } |
| |
| private int mSignalLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; |
| |
| // We use a separate instance than mPhoneStateListener because the lifetimes are different. |
| private final PhoneStateListener mSignalStrengthListener = new PhoneStateListener() { |
| @Override |
| public void onSignalStrengthsChanged(final SignalStrength signalStrength) { |
| mSignalLevel = getLevel(signalStrength); |
| } |
| }; |
| |
| public void registerForSignalStrength() { |
| mTelephonyManager.listen( |
| mSignalStrengthListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); |
| } |
| |
| public void unregisterForSignalStrength() { |
| mTelephonyManager.listen(mSignalStrengthListener, PhoneStateListener.LISTEN_NONE); |
| } |
| |
| /** |
| * @param subId This is ignored because TelephonyManager does not support it. |
| * @return Signal strength as level 0..4 |
| */ |
| public int getSignalLevel(final int subId) { |
| return mSignalLevel; |
| } |
| |
| private static final int SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0; |
| private static final int SIGNAL_STRENGTH_POOR = 1; |
| private static final int SIGNAL_STRENGTH_MODERATE = 2; |
| private static final int SIGNAL_STRENGTH_GOOD = 3; |
| private static final int SIGNAL_STRENGTH_GREAT = 4; |
| |
| private static final int GSM_SIGNAL_STRENGTH_GREAT = 12; |
| private static final int GSM_SIGNAL_STRENGTH_GOOD = 8; |
| private static final int GSM_SIGNAL_STRENGTH_MODERATE = 8; |
| |
| private static int getLevel(final SignalStrength signalStrength) { |
| if (signalStrength.isGsm()) { |
| // From frameworks/base/telephony/java/android/telephony/CellSignalStrengthGsm.java |
| |
| // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5 |
| // asu = 0 (-113dB or less) is very weak |
| // signal, its better to show 0 bars to the user in such cases. |
| // asu = 99 is a special case, where the signal strength is unknown. |
| final int asu = signalStrength.getGsmSignalStrength(); |
| if (asu <= 2 || asu == 99) return SIGNAL_STRENGTH_NONE_OR_UNKNOWN; |
| else if (asu >= GSM_SIGNAL_STRENGTH_GREAT) return SIGNAL_STRENGTH_GREAT; |
| else if (asu >= GSM_SIGNAL_STRENGTH_GOOD) return SIGNAL_STRENGTH_GOOD; |
| else if (asu >= GSM_SIGNAL_STRENGTH_MODERATE) return SIGNAL_STRENGTH_MODERATE; |
| else return SIGNAL_STRENGTH_POOR; |
| } else { |
| // From frameworks/base/telephony/java/android/telephony/CellSignalStrengthCdma.java |
| |
| final int cdmaLevel = getCdmaLevel(signalStrength); |
| final int evdoLevel = getEvdoLevel(signalStrength); |
| if (evdoLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) { |
| /* We don't know evdo, use cdma */ |
| return getCdmaLevel(signalStrength); |
| } else if (cdmaLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) { |
| /* We don't know cdma, use evdo */ |
| return getEvdoLevel(signalStrength); |
| } else { |
| /* We know both, use the lowest level */ |
| return cdmaLevel < evdoLevel ? cdmaLevel : evdoLevel; |
| } |
| } |
| } |
| |
| /** |
| * Get cdma as level 0..4 |
| */ |
| private static int getCdmaLevel(final SignalStrength signalStrength) { |
| final int cdmaDbm = signalStrength.getCdmaDbm(); |
| final int cdmaEcio = signalStrength.getCdmaEcio(); |
| int levelDbm; |
| int levelEcio; |
| if (cdmaDbm >= -75) levelDbm = SIGNAL_STRENGTH_GREAT; |
| else if (cdmaDbm >= -85) levelDbm = SIGNAL_STRENGTH_GOOD; |
| else if (cdmaDbm >= -95) levelDbm = SIGNAL_STRENGTH_MODERATE; |
| else if (cdmaDbm >= -100) levelDbm = SIGNAL_STRENGTH_POOR; |
| else levelDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; |
| // Ec/Io are in dB*10 |
| if (cdmaEcio >= -90) levelEcio = SIGNAL_STRENGTH_GREAT; |
| else if (cdmaEcio >= -110) levelEcio = SIGNAL_STRENGTH_GOOD; |
| else if (cdmaEcio >= -130) levelEcio = SIGNAL_STRENGTH_MODERATE; |
| else if (cdmaEcio >= -150) levelEcio = SIGNAL_STRENGTH_POOR; |
| else levelEcio = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; |
| final int level = (levelDbm < levelEcio) ? levelDbm : levelEcio; |
| return level; |
| } |
| /** |
| * Get Evdo as level 0..4 |
| */ |
| private static int getEvdoLevel(final SignalStrength signalStrength) { |
| final int evdoDbm = signalStrength.getEvdoDbm(); |
| final int evdoSnr = signalStrength.getEvdoSnr(); |
| int levelEvdoDbm; |
| int levelEvdoSnr; |
| if (evdoDbm >= -65) levelEvdoDbm = SIGNAL_STRENGTH_GREAT; |
| else if (evdoDbm >= -75) levelEvdoDbm = SIGNAL_STRENGTH_GOOD; |
| else if (evdoDbm >= -90) levelEvdoDbm = SIGNAL_STRENGTH_MODERATE; |
| else if (evdoDbm >= -105) levelEvdoDbm = SIGNAL_STRENGTH_POOR; |
| else levelEvdoDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; |
| if (evdoSnr >= 7) levelEvdoSnr = SIGNAL_STRENGTH_GREAT; |
| else if (evdoSnr >= 5) levelEvdoSnr = SIGNAL_STRENGTH_GOOD; |
| else if (evdoSnr >= 3) levelEvdoSnr = SIGNAL_STRENGTH_MODERATE; |
| else if (evdoSnr >= 1) levelEvdoSnr = SIGNAL_STRENGTH_POOR; |
| else levelEvdoSnr = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; |
| final int level = (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr; |
| return level; |
| } |
| } |