diff options
Diffstat (limited to 'src/com/android/messaging/util/ConnectivityUtil.java')
-rw-r--r-- | src/com/android/messaging/util/ConnectivityUtil.java | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/src/com/android/messaging/util/ConnectivityUtil.java b/src/com/android/messaging/util/ConnectivityUtil.java new file mode 100644 index 0000000..49f6e0a --- /dev/null +++ b/src/com/android/messaging/util/ConnectivityUtil.java @@ -0,0 +1,247 @@ +/* + * 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; + } +} |