/*
* Copyright (C) 2010 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.systemui.statusbar.policy;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.provider.Settings;
import android.provider.Telephony;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.util.Slog;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.app.IBatteryStats;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.cdma.EriInfo;
import com.android.server.am.BatteryStatsService;
import com.android.internal.util.AsyncChannel;
import com.android.systemui.R;
public class NetworkController extends BroadcastReceiver {
// debug
static final String TAG = "StatusBar.NetworkController";
static final boolean DEBUG = false;
static final boolean CHATTY = false; // additional diagnostics, but not logspew
// telephony
boolean mHspaDataDistinguishable;
final TelephonyManager mPhone;
boolean mDataConnected;
IccCard.State mSimState = IccCard.State.READY;
int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
int mDataState = TelephonyManager.DATA_DISCONNECTED;
int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
ServiceState mServiceState;
SignalStrength mSignalStrength;
int[] mDataIconList = TelephonyIcons.DATA_G[0];
String mNetworkName;
String mNetworkNameDefault;
String mNetworkNameSeparator;
int mPhoneSignalIconId;
int mDataDirectionIconId; // data + data direction on phones
int mDataSignalIconId;
int mDataTypeIconId;
boolean mDataActive;
int mMobileActivityIconId; // overlay arrows for data direction
int mLastSignalLevel;
String mContentDescriptionPhoneSignal;
String mContentDescriptionWifi;
String mContentDescriptionCombinedSignal;
String mContentDescriptionDataType;
// wifi
final WifiManager mWifiManager;
AsyncChannel mWifiChannel;
boolean mWifiEnabled, mWifiConnected;
int mWifiRssi, mWifiLevel;
String mWifiSsid;
int mWifiIconId = 0;
int mWifiActivityIconId = 0; // overlay arrows for wifi direction
int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE;
// bluetooth
private boolean mBluetoothTethered = false;
private int mBluetoothTetherIconId =
com.android.internal.R.drawable.stat_sys_tether_bluetooth;
// data connectivity (regardless of state, can we access the internet?)
// state of inet connection - 0 not connected, 100 connected
private int mInetCondition = 0;
private static final int INET_CONDITION_THRESHOLD = 50;
private boolean mAirplaneMode = false;
// our ui
Context mContext;
ArrayList<ImageView> mPhoneSignalIconViews = new ArrayList<ImageView>();
ArrayList<ImageView> mDataDirectionIconViews = new ArrayList<ImageView>();
ArrayList<ImageView> mDataDirectionOverlayIconViews = new ArrayList<ImageView>();
ArrayList<ImageView> mWifiIconViews = new ArrayList<ImageView>();
ArrayList<ImageView> mCombinedSignalIconViews = new ArrayList<ImageView>();
ArrayList<ImageView> mDataTypeIconViews = new ArrayList<ImageView>();
ArrayList<TextView> mLabelViews = new ArrayList<TextView>();
ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
int mLastPhoneSignalIconId = -1;
int mLastDataDirectionIconId = -1;
int mLastDataDirectionOverlayIconId = -1;
int mLastWifiIconId = -1;
int mLastCombinedSignalIconId = -1;
int mLastDataTypeIconId = -1;
String mLastLabel = "";
private boolean mHasMobileDataFeature;
boolean mDataAndWifiStacked = false;
// yuck -- stop doing this here and put it in the framework
IBatteryStats mBatteryStats;
public interface SignalCluster {
void setWifiIndicators(boolean visible, int strengthIcon, int activityIcon,
String contentDescription);
void setMobileDataIndicators(boolean visible, int strengthIcon, int activityIcon,
int typeIcon, String contentDescription, String typeContentDescription);
void setIsAirplaneMode(boolean is);
}
/**
* Construct this controller object and register for updates.
*/
public NetworkController(Context context) {
mContext = context;
ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
mHasMobileDataFeature = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
// set up the default wifi icon, used when no radios have ever appeared
updateWifiIcons();
// telephony
mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
mPhone.listen(mPhoneStateListener,
PhoneStateListener.LISTEN_SERVICE_STATE
| PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
| PhoneStateListener.LISTEN_CALL_STATE
| PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
| PhoneStateListener.LISTEN_DATA_ACTIVITY);
mHspaDataDistinguishable = mContext.getResources().getBoolean(
R.bool.config_hspa_data_distinguishable);
mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator);
mNetworkNameDefault = mContext.getString(
com.android.internal.R.string.lockscreen_carrier_default);
mNetworkName = mNetworkNameDefault;
// wifi
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Handler handler = new WifiHandler();
mWifiChannel = new AsyncChannel();
Messenger wifiMessenger = mWifiManager.getMessenger();
if (wifiMessenger != null) {
mWifiChannel.connect(mContext, handler, wifiMessenger);
}
// broadcasts
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
filter.addAction(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
context.registerReceiver(this, filter);
// AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
updateAirplaneMode();
// yuck
mBatteryStats = BatteryStatsService.getService();
}
public void addPhoneSignalIconView(ImageView v) {
mPhoneSignalIconViews.add(v);
}
public void addDataDirectionIconView(ImageView v) {
mDataDirectionIconViews.add(v);
}
public void addDataDirectionOverlayIconView(ImageView v) {
mDataDirectionOverlayIconViews.add(v);
}
public void addWifiIconView(ImageView v) {
mWifiIconViews.add(v);
}
public void addCombinedSignalIconView(ImageView v) {
mCombinedSignalIconViews.add(v);
}
public void addDataTypeIconView(ImageView v) {
mDataTypeIconViews.add(v);
}
public void addLabelView(TextView v) {
mLabelViews.add(v);
}
public void addSignalCluster(SignalCluster cluster) {
mSignalClusters.add(cluster);
cluster.setWifiIndicators(
mWifiConnected, // only show wifi in the cluster if connected
mWifiIconId,
mWifiActivityIconId,
mContentDescriptionWifi);
cluster.setMobileDataIndicators(
mHasMobileDataFeature,
mPhoneSignalIconId,
mMobileActivityIconId,
mDataTypeIconId,
mContentDescriptionPhoneSignal,
mContentDescriptionDataType);
}
public void setStackedMode(boolean stacked) {
mDataAndWifiStacked = true;
}
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
|| action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
|| action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
updateWifiState(intent);
refreshViews();
} else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
updateSimState(intent);
updateDataIcon();
refreshViews();
} else if (action.equals(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION)) {
updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false),
intent.getStringExtra(Telephony.Intents.EXTRA_SPN),
intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false),
intent.getStringExtra(Telephony.Intents.EXTRA_PLMN));
refreshViews();
} else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
updateConnectivity(intent);
refreshViews();
} else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
refreshViews();
} else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
updateAirplaneMode();
refreshViews();
}
}
// ===== Telephony ==============================================================
PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
if (DEBUG) {
Slog.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
}
mSignalStrength = signalStrength;
updateTelephonySignalStrength();
refreshViews();
}
@Override
public void onServiceStateChanged(ServiceState state) {
if (DEBUG) {
Slog.d(TAG, "onServiceStateChanged state=" + state.getState());
}
mServiceState = state;
updateTelephonySignalStrength();
updateDataNetType();
updateDataIcon();
refreshViews();
}
@Override
public void onCallStateChanged(int state, String incomingNumber) {
if (DEBUG) {
Slog.d(TAG, "onCallStateChanged state=" + state);
}
// In cdma, if a voice call is made, RSSI should switch to 1x.
if (isCdma()) {
updateTelephonySignalStrength();
refreshViews();
}
}
@Override
public void onDataConnectionStateChanged(int state, int networkType) {
if (DEBUG) {
Slog.d(TAG, "onDataConnectionStateChanged: state=" + state
+ " type=" + networkType);
}
mDataState = state;
mDataNetType = networkType;
updateDataNetType();
updateDataIcon();
refreshViews();
}
@Override
public void onDataActivity(int direction) {
if (DEBUG) {
Slog.d(TAG, "onDataActivity: direction=" + direction);
}
mDataActivity = direction;
updateDataIcon();
refreshViews();
}
};
private final void updateSimState(Intent intent) {
String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
mSimState = IccCard.State.ABSENT;
}
else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
mSimState = IccCard.State.READY;
}
else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
mSimState = IccCard.State.PIN_REQUIRED;
}
else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
mSimState = IccCard.State.PUK_REQUIRED;
}
else {
mSimState = IccCard.State.NETWORK_LOCKED;
}
} else {
mSimState = IccCard.State.UNKNOWN;
}
}
private boolean isCdma() {
return (mSignalStrength != null) && !mSignalStrength.isGsm();
}
private boolean hasService() {
if (mServiceState != null) {
switch (mServiceState.getState()) {
case ServiceState.STATE_OUT_OF_SERVICE:
case ServiceState.STATE_POWER_OFF:
return false;
default:
return true;
}
} else {
return false;
}
}
private void updateAirplaneMode() {
mAirplaneMode = (Settings.System.getInt(mContext.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, 0) == 1);
}
private final void updateTelephonySignalStrength() {
if (!hasService()) {
if (CHATTY) Slog.d(TAG, "updateTelephonySignalStrength: !hasService()");
mPhoneSignalIconId = R.drawable.stat_sys_signal_0;
mDataSignalIconId = R.drawable.stat_sys_signal_0;
} else {
if (mSignalStrength == null) {
if (CHATTY) Slog.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
mPhoneSignalIconId = R.drawable.stat_sys_signal_0;
mDataSignalIconId = R.drawable.stat_sys_signal_0;
mContentDescriptionPhoneSignal = mContext.getString(
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
} else {
int iconLevel;
int[] iconList;
mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
if (isCdma()) {
if (isCdmaEri()) {
iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
} else {
iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
}
} else {
// Though mPhone is a Manager, this call is not an IPC
if (mPhone.isNetworkRoaming()) {
iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
} else {
iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
}
}
mPhoneSignalIconId = iconList[iconLevel];
mContentDescriptionPhoneSignal = mContext.getString(
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
}
}
}
private final void updateDataNetType() {
switch (mDataNetType) {
case TelephonyManager.NETWORK_TYPE_UNKNOWN:
mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
mDataTypeIconId = 0;
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_gprs);
break;
case TelephonyManager.NETWORK_TYPE_EDGE:
mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
mDataTypeIconId = R.drawable.stat_sys_data_connected_e;
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_edge);
break;
case TelephonyManager.NETWORK_TYPE_UMTS:
mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_3g);
break;
case TelephonyManager.NETWORK_TYPE_HSDPA:
case TelephonyManager.NETWORK_TYPE_HSUPA:
case TelephonyManager.NETWORK_TYPE_HSPA:
case TelephonyManager.NETWORK_TYPE_HSPAP:
if (mHspaDataDistinguishable) {
mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
mDataTypeIconId = R.drawable.stat_sys_data_connected_h;
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_3_5g);
} else {
mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_3g);
}
break;
case TelephonyManager.NETWORK_TYPE_CDMA:
// display 1xRTT for IS95A/B
mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_cdma);
break;
case TelephonyManager.NETWORK_TYPE_1xRTT:
mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_cdma);
break;
case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
case TelephonyManager.NETWORK_TYPE_EHRPD:
mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_3g);
break;
case TelephonyManager.NETWORK_TYPE_LTE:
mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_4g);
break;
default:
mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
mDataTypeIconId = R.drawable.stat_sys_data_connected_g;
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_gprs);
break;
}
if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
}
}
boolean isCdmaEri() {
if (mServiceState != null) {
final int iconIndex = mServiceState.getCdmaEriIconIndex();
if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
final int iconMode = mServiceState.getCdmaEriIconMode();
if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
|| iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
return true;
}
}
}
return false;
}
private final void updateDataIcon() {
int iconId;
boolean visible = true;
if (!isCdma()) {
// GSM case, we have to check also the sim state
if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
switch (mDataActivity) {
case TelephonyManager.DATA_ACTIVITY_IN:
iconId = mDataIconList[1];
break;
case TelephonyManager.DATA_ACTIVITY_OUT:
iconId = mDataIconList[2];
break;
case TelephonyManager.DATA_ACTIVITY_INOUT:
iconId = mDataIconList[3];
break;
default:
iconId = mDataIconList[0];
break;
}
mDataDirectionIconId = iconId;
} else {
iconId = 0;
visible = false;
}
} else {
iconId = R.drawable.stat_sys_no_sim;
visible = false; // no SIM? no data
}
} else {
// CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
switch (mDataActivity) {
case TelephonyManager.DATA_ACTIVITY_IN:
iconId = mDataIconList[1];
break;
case TelephonyManager.DATA_ACTIVITY_OUT:
iconId = mDataIconList[2];
break;
case TelephonyManager.DATA_ACTIVITY_INOUT:
iconId = mDataIconList[3];
break;
case TelephonyManager.DATA_ACTIVITY_DORMANT:
default:
iconId = mDataIconList[0];
break;
}
} else {
iconId = 0;
visible = false;
}
}
// yuck - this should NOT be done by the status bar
long ident = Binder.clearCallingIdentity();
try {
mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(ident);
}
mDataDirectionIconId = iconId;
mDataConnected = visible;
}
void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
if (false) {
Slog.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+ " showPlmn=" + showPlmn + " plmn=" + plmn);
}
StringBuilder str = new StringBuilder();
boolean something = false;
if (showPlmn && plmn != null) {
str.append(plmn);
something = true;
}
if (showSpn && spn != null) {
if (something) {
str.append(mNetworkNameSeparator);
}
str.append(spn);
something = true;
}
if (something) {
mNetworkName = str.toString();
} else {
mNetworkName = mNetworkNameDefault;
}
}
// ===== Wifi ===================================================================
class WifiHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
mWifiChannel.sendMessage(Message.obtain(this,
AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
} else {
Slog.e(TAG, "Failed to connect to wifi");
}
break;
case WifiManager.DATA_ACTIVITY_NOTIFICATION:
if (msg.arg1 != mWifiActivity) {
mWifiActivity = msg.arg1;
refreshViews();
}
break;
default:
//Ignore
break;
}
}
}
private void updateWifiState(Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
} else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
final NetworkInfo networkInfo = (NetworkInfo)
intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
boolean wasConnected = mWifiConnected;
mWifiConnected = networkInfo != null && networkInfo.isConnected();
// If we just connected, grab the inintial signal strength and ssid
if (mWifiConnected && !wasConnected) {
// try getting it out of the intent first
WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
if (info == null) {
info = mWifiManager.getConnectionInfo();
}
if (info != null) {
mWifiSsid = huntForSsid(info);
} else {
mWifiSsid = null;
}
} else if (!mWifiConnected) {
mWifiSsid = null;
}
// Apparently the wifi level is not stable at this point even if we've just connected to
// the network; we need to wait for an RSSI_CHANGED_ACTION for that. So let's just set
// it to 0 for now
mWifiLevel = 0;
mWifiRssi = -200;
} else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
if (mWifiConnected) {
mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
mWifiLevel = WifiManager.calculateSignalLevel(
mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT);
}
}
updateWifiIcons();
}
private void updateWifiIcons() {
if (mWifiConnected) {
mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
mContentDescriptionWifi = mContext.getString(
AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]);
} else {
if (mDataAndWifiStacked) {
mWifiIconId = 0;
} else {
mWifiIconId = mWifiEnabled ? WifiIcons.WIFI_SIGNAL_STRENGTH[0][0] : 0;
}
mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
}
}
private String huntForSsid(WifiInfo info) {
String ssid = info.getSSID();
if (ssid != null) {
return ssid;
}
// OK, it's not in the connectionInfo; we have to go hunting for it
List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
for (WifiConfiguration net : networks) {
if (net.networkId == info.getNetworkId()) {
return net.SSID;
}
}
return null;
}
// ===== Full or limited Internet connectivity ==================================
private void updateConnectivity(Intent intent) {
if (CHATTY) {
Slog.d(TAG, "updateConnectivity: intent=" + intent);
}
NetworkInfo info = (NetworkInfo)(intent.getParcelableExtra(
ConnectivityManager.EXTRA_NETWORK_INFO));
int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
if (CHATTY) {
Slog.d(TAG, "updateConnectivity: networkInfo=" + info);
Slog.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
}
mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) {
mBluetoothTethered = info.isConnected() ? true: false;
} else {
mBluetoothTethered = false;
}
// We want to update all the icons, all at once, for any condition change
updateDataNetType();
updateDataIcon();
updateTelephonySignalStrength();
updateWifiIcons();
}
// ===== Update the views =======================================================
void refreshViews() {
Context context = mContext;
int combinedSignalIconId = 0;
int combinedActivityIconId = 0;
String label = "";
int N;
if (mDataConnected) {
label = mNetworkName;
combinedSignalIconId = mDataSignalIconId;
switch (mDataActivity) {
case TelephonyManager.DATA_ACTIVITY_IN:
mMobileActivityIconId = R.drawable.stat_sys_signal_in;
break;
case TelephonyManager.DATA_ACTIVITY_OUT:
mMobileActivityIconId = R.drawable.stat_sys_signal_out;
break;
case TelephonyManager.DATA_ACTIVITY_INOUT:
mMobileActivityIconId = R.drawable.stat_sys_signal_inout;
break;
default:
mMobileActivityIconId = 0;
break;
}
combinedActivityIconId = mMobileActivityIconId;
combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
mContentDescriptionCombinedSignal = mContentDescriptionDataType;
}
if (mWifiConnected) {
if (mWifiSsid == null) {
label = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
mWifiActivityIconId = 0; // no wifis, no bits
} else {
label = mWifiSsid;
switch (mWifiActivity) {
case WifiManager.DATA_ACTIVITY_IN:
mWifiActivityIconId = R.drawable.stat_sys_wifi_in;
break;
case WifiManager.DATA_ACTIVITY_OUT:
mWifiActivityIconId = R.drawable.stat_sys_wifi_out;
break;
case WifiManager.DATA_ACTIVITY_INOUT:
mWifiActivityIconId = R.drawable.stat_sys_wifi_inout;
break;
case WifiManager.DATA_ACTIVITY_NONE:
mWifiActivityIconId = 0;
break;
}
}
combinedActivityIconId = mWifiActivityIconId;
combinedSignalIconId = mWifiIconId; // set by updateWifiIcons()
mContentDescriptionCombinedSignal = mContentDescriptionWifi;
}
if (mBluetoothTethered) {
label = mContext.getString(R.string.bluetooth_tethered);
combinedSignalIconId = mBluetoothTetherIconId;
mContentDescriptionCombinedSignal = mContext.getString(
R.string.accessibility_bluetooth_tether);
}
if (mAirplaneMode &&
(mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
// Only display the flight-mode icon if not in "emergency calls only" mode.
label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal
= mContext.getString(R.string.accessibility_airplane_mode);
// look again; your radios are now airplanes
mPhoneSignalIconId = mDataSignalIconId = R.drawable.stat_sys_signal_flightmode;
mDataTypeIconId = 0;
combinedSignalIconId = mDataSignalIconId;
}
else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered) {
// pretty much totally disconnected
label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
// On devices without mobile radios, we want to show the wifi icon
combinedSignalIconId =
mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
mContentDescriptionCombinedSignal = mHasMobileDataFeature
? mContentDescriptionDataType : mContentDescriptionWifi;
if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
} else {
mDataTypeIconId = 0;
}
}
if (DEBUG) {
Slog.d(TAG, "refreshViews connected={"
+ (mWifiConnected?" wifi":"")
+ (mDataConnected?" data":"")
+ " } level="
+ ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel()))
+ " combinedSignalIconId=0x"
+ Integer.toHexString(combinedSignalIconId)
+ "/" + getResourceName(combinedSignalIconId)
+ " combinedActivityIconId=0x" + Integer.toHexString(combinedActivityIconId)
+ " mAirplaneMode=" + mAirplaneMode
+ " mDataActivity=" + mDataActivity
+ " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId)
+ " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId)
+ " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId)
+ " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId)
+ " mWifiIconId=0x" + Integer.toHexString(mWifiIconId)
+ " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId));
}
if (mLastPhoneSignalIconId != mPhoneSignalIconId
|| mLastDataDirectionOverlayIconId != combinedActivityIconId
|| mLastWifiIconId != mWifiIconId
|| mLastDataTypeIconId != mDataTypeIconId)
{
// NB: the mLast*s will be updated later
for (SignalCluster cluster : mSignalClusters) {
cluster.setWifiIndicators(
mWifiConnected, // only show wifi in the cluster if connected
mWifiIconId,
mWifiActivityIconId,
mContentDescriptionWifi);
cluster.setMobileDataIndicators(
mHasMobileDataFeature,
mPhoneSignalIconId,
mMobileActivityIconId,
mDataTypeIconId,
mContentDescriptionPhoneSignal,
mContentDescriptionDataType);
cluster.setIsAirplaneMode(mAirplaneMode);
}
}
// the phone icon on phones
if (mLastPhoneSignalIconId != mPhoneSignalIconId) {
mLastPhoneSignalIconId = mPhoneSignalIconId;
N = mPhoneSignalIconViews.size();
for (int i=0; i<N; i++) {
final ImageView v = mPhoneSignalIconViews.get(i);
v.setImageResource(mPhoneSignalIconId);
v.setContentDescription(mContentDescriptionPhoneSignal);
}
}
// the data icon on phones
if (mLastDataDirectionIconId != mDataDirectionIconId) {
mLastDataDirectionIconId = mDataDirectionIconId;
N = mDataDirectionIconViews.size();
for (int i=0; i<N; i++) {
final ImageView v = mDataDirectionIconViews.get(i);
v.setImageResource(mDataDirectionIconId);
v.setContentDescription(mContentDescriptionDataType);
}
}
// the wifi icon on phones
if (mLastWifiIconId != mWifiIconId) {
mLastWifiIconId = mWifiIconId;
N = mWifiIconViews.size();
for (int i=0; i<N; i++) {
final ImageView v = mWifiIconViews.get(i);
if (mWifiIconId == 0) {
v.setVisibility(View.INVISIBLE);
} else {
v.setVisibility(View.VISIBLE);
v.setImageResource(mWifiIconId);
v.setContentDescription(mContentDescriptionWifi);
}
}
}
// the combined data signal icon
if (mLastCombinedSignalIconId != combinedSignalIconId) {
mLastCombinedSignalIconId = combinedSignalIconId;
N = mCombinedSignalIconViews.size();
for (int i=0; i<N; i++) {
final ImageView v = mCombinedSignalIconViews.get(i);
v.setImageResource(combinedSignalIconId);
v.setContentDescription(mContentDescriptionCombinedSignal);
}
}
// the data network type overlay
if (mLastDataTypeIconId != mDataTypeIconId) {
mLastDataTypeIconId = mDataTypeIconId;
N = mDataTypeIconViews.size();
for (int i=0; i<N; i++) {
final ImageView v = mDataTypeIconViews.get(i);
if (mDataTypeIconId == 0) {
v.setVisibility(View.INVISIBLE);
} else {
v.setVisibility(View.VISIBLE);
v.setImageResource(mDataTypeIconId);
v.setContentDescription(mContentDescriptionDataType);
}
}
}
// the data direction overlay
if (mLastDataDirectionOverlayIconId != combinedActivityIconId) {
if (DEBUG) {
Slog.d(TAG, "changing data overlay icon id to " + combinedActivityIconId);
}
mLastDataDirectionOverlayIconId = combinedActivityIconId;
N = mDataDirectionOverlayIconViews.size();
for (int i=0; i<N; i++) {
final ImageView v = mDataDirectionOverlayIconViews.get(i);
if (combinedActivityIconId == 0) {
v.setVisibility(View.INVISIBLE);
} else {
v.setVisibility(View.VISIBLE);
v.setImageResource(combinedActivityIconId);
v.setContentDescription(mContentDescriptionDataType);
}
}
}
// the label in the notification panel
if (!mLastLabel.equals(label)) {
mLastLabel = label;
N = mLabelViews.size();
for (int i=0; i<N; i++) {
TextView v = mLabelViews.get(i);
v.setText(label);
}
}
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("NetworkController state:");
pw.println(" - telephony ------");
pw.print(" hasService()=");
pw.println(hasService());
pw.print(" mHspaDataDistinguishable=");
pw.println(mHspaDataDistinguishable);
pw.print(" mDataConnected=");
pw.println(mDataConnected);
pw.print(" mSimState=");
pw.println(mSimState);
pw.print(" mPhoneState=");
pw.println(mPhoneState);
pw.print(" mDataState=");
pw.println(mDataState);
pw.print(" mDataActivity=");
pw.println(mDataActivity);
pw.print(" mDataNetType=");
pw.print(mDataNetType);
pw.print("/");
pw.println(TelephonyManager.getNetworkTypeName(mDataNetType));
pw.print(" mServiceState=");
pw.println(mServiceState);
pw.print(" mSignalStrength=");
pw.println(mSignalStrength);
pw.print(" mLastSignalLevel=");
pw.println(mLastSignalLevel);
pw.print(" mNetworkName=");
pw.println(mNetworkName);
pw.print(" mNetworkNameDefault=");
pw.println(mNetworkNameDefault);
pw.print(" mNetworkNameSeparator=");
pw.println(mNetworkNameSeparator.replace("\n","\\n"));
pw.print(" mPhoneSignalIconId=0x");
pw.print(Integer.toHexString(mPhoneSignalIconId));
pw.print("/");
pw.println(getResourceName(mPhoneSignalIconId));
pw.print(" mDataDirectionIconId=");
pw.print(Integer.toHexString(mDataDirectionIconId));
pw.print("/");
pw.println(getResourceName(mDataDirectionIconId));
pw.print(" mDataSignalIconId=");
pw.print(Integer.toHexString(mDataSignalIconId));
pw.print("/");
pw.println(getResourceName(mDataSignalIconId));
pw.print(" mDataTypeIconId=");
pw.print(Integer.toHexString(mDataTypeIconId));
pw.print("/");
pw.println(getResourceName(mDataTypeIconId));
pw.println(" - wifi ------");
pw.print(" mWifiEnabled=");
pw.println(mWifiEnabled);
pw.print(" mWifiConnected=");
pw.println(mWifiConnected);
pw.print(" mWifiRssi=");
pw.println(mWifiRssi);
pw.print(" mWifiLevel=");
pw.println(mWifiLevel);
pw.print(" mWifiSsid=");
pw.println(mWifiSsid);
pw.print(String.format(" mWifiIconId=0x%08x/%s",
mWifiIconId, getResourceName(mWifiIconId)));
pw.print(" mWifiActivity=");
pw.println(mWifiActivity);
pw.println(" - Bluetooth ----");
pw.print(" mBtReverseTethered=");
pw.println(mBluetoothTethered);
pw.println(" - connectivity ------");
pw.print(" mInetCondition=");
pw.println(mInetCondition);
pw.println(" - icons ------");
pw.print(" mLastPhoneSignalIconId=0x");
pw.print(Integer.toHexString(mLastPhoneSignalIconId));
pw.print("/");
pw.println(getResourceName(mLastPhoneSignalIconId));
pw.print(" mLastDataDirectionIconId=0x");
pw.print(Integer.toHexString(mLastDataDirectionIconId));
pw.print("/");
pw.println(getResourceName(mLastDataDirectionIconId));
pw.print(" mLastDataDirectionOverlayIconId=0x");
pw.print(Integer.toHexString(mLastDataDirectionOverlayIconId));
pw.print("/");
pw.println(getResourceName(mLastDataDirectionOverlayIconId));
pw.print(" mLastWifiIconId=0x");
pw.print(Integer.toHexString(mLastWifiIconId));
pw.print("/");
pw.println(getResourceName(mLastWifiIconId));
pw.print(" mLastCombinedSignalIconId=0x");
pw.print(Integer.toHexString(mLastCombinedSignalIconId));
pw.print("/");
pw.println(getResourceName(mLastCombinedSignalIconId));
pw.print(" mLastDataTypeIconId=0x");
pw.print(Integer.toHexString(mLastDataTypeIconId));
pw.print("/");
pw.println(getResourceName(mLastCombinedSignalIconId));
pw.print(" mLastLabel=");
pw.print(mLastLabel);
pw.println("");
}
private String getResourceName(int resId) {
if (resId != 0) {
final Resources res = mContext.getResources();
try {
return res.getResourceName(resId);
} catch (android.content.res.Resources.NotFoundException ex) {
return "(unknown)";
}
} else {
return "(null)";
}
}
}