am 0727a865: Merge "Add network condition reporting." into gingerbread

Merge commit '0727a865d83b944c2fecc0bf1228a36976fe5300' into gingerbread-plus-aosp

* commit '0727a865d83b944c2fecc0bf1228a36976fe5300':
  Add network condition reporting.
This commit is contained in:
Robert Greenwalt
2010-09-09 09:49:15 -07:00
committed by Android Git Automerger
6 changed files with 258 additions and 73 deletions

View File

@ -105,6 +105,14 @@ public class ConnectivityManager
* it with {@link android.content.Intent#getStringExtra(String)}. * it with {@link android.content.Intent#getStringExtra(String)}.
*/ */
public static final String EXTRA_EXTRA_INFO = "extraInfo"; public static final String EXTRA_EXTRA_INFO = "extraInfo";
/**
* The lookup key for an int that provides information about
* our connection to the internet at large. 0 indicates no connection,
* 100 indicates a great connection. Retrieve it with
* {@link android.content.Intent@getIntExtra(String)}.
* {@hide}
*/
public static final String EXTRA_INET_CONDITION = "inetCondition";
/** /**
* Broadcast Action: The setting for background data usage has changed * Broadcast Action: The setting for background data usage has changed
@ -548,5 +556,17 @@ public class ConnectivityManager
} catch (RemoteException e) { } catch (RemoteException e) {
return TETHER_ERROR_SERVICE_UNAVAIL; return TETHER_ERROR_SERVICE_UNAVAIL;
} }
} }
/**
* @param networkType The type of network you want to report on
* @param percentage The quality of the connection 0 is bad, 100 is good
* {@hide}
*/
public void reportInetCondition(int networkType, int percentage) {
try {
mService.reportInetCondition(networkType, percentage);
} catch (RemoteException e) {
}
}
} }

View File

@ -74,4 +74,6 @@ interface IConnectivityManager
String[] getTetherableUsbRegexs(); String[] getTetherableUsbRegexs();
String[] getTetherableWifiRegexs(); String[] getTetherableWifiRegexs();
void reportInetCondition(int networkType, int percentage);
} }

View File

@ -63,6 +63,15 @@ public abstract class NetworkStateTracker extends Handler {
public static final int EVENT_ROAMING_CHANGED = 5; public static final int EVENT_ROAMING_CHANGED = 5;
public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 6; public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 6;
public static final int EVENT_RESTORE_DEFAULT_NETWORK = 7; public static final int EVENT_RESTORE_DEFAULT_NETWORK = 7;
/**
* arg1: network type
* arg2: condition (0 bad, 100 good)
*/
public static final int EVENT_INET_CONDITION_CHANGE = 8;
/**
* arg1: network type
*/
public static final int EVENT_INET_CONDITION_HOLD_END = 9;
public NetworkStateTracker(Context context, public NetworkStateTracker(Context context,
Handler target, Handler target,

View File

@ -3427,6 +3427,21 @@ public final class Settings {
public static final String DOWNLOAD_MAX_BYTES_OVER_MOBILE = public static final String DOWNLOAD_MAX_BYTES_OVER_MOBILE =
"download_manager_max_bytes_over_mobile"; "download_manager_max_bytes_over_mobile";
/**
* ms during which to consume extra events related to Inet connection condition
* after a transtion to fully-connected
* @hide
*/
public static final String INET_CONDITION_DEBOUNCE_UP_DELAY =
"inet_condition_debounce_up_delay";
/**
* ms during which to consume extra events related to Inet connection condtion
* after a transtion to partly-connected
* @hide
*/
public static final String INET_CONDITION_DEBOUNCE_DOWN_DELAY =
"inet_condition_debounce_down_delay";
/** /**
* @hide * @hide

View File

@ -36,6 +36,7 @@ import android.location.LocationManager;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.Ringtone; import android.media.Ringtone;
import android.media.RingtoneManager; import android.media.RingtoneManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.net.Uri; import android.net.Uri;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
@ -91,6 +92,8 @@ public class StatusBarPolicy {
private static final int AM_PM_STYLE = AM_PM_STYLE_GONE; private static final int AM_PM_STYLE = AM_PM_STYLE_GONE;
private static final int INET_CONDITION_THRESHOLD = 50;
private final Context mContext; private final Context mContext;
private final StatusBarManager mService; private final StatusBarManager mService;
private final Handler mHandler = new StatusBarHandler(); private final Handler mHandler = new StatusBarHandler();
@ -232,42 +235,62 @@ public class StatusBarPolicy {
}; };
//***** Data connection icons //***** Data connection icons
private int[] mDataIconList = sDataNetType_g; private int[] mDataIconList = sDataNetType_g[0];
//GSM/UMTS //GSM/UMTS
private static final int[] sDataNetType_g = new int[] { private static final int[][] sDataNetType_g = {
R.drawable.stat_sys_data_connected_g, { R.drawable.stat_sys_data_connected_g,
R.drawable.stat_sys_data_in_g, R.drawable.stat_sys_data_in_g,
R.drawable.stat_sys_data_out_g, R.drawable.stat_sys_data_out_g,
R.drawable.stat_sys_data_inandout_g, R.drawable.stat_sys_data_inandout_g },
{ R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0 }
}; };
private static final int[] sDataNetType_3g = new int[] { private static final int[][] sDataNetType_3g = {
R.drawable.stat_sys_data_connected_3g, { R.drawable.stat_sys_data_connected_3g,
R.drawable.stat_sys_data_in_3g, R.drawable.stat_sys_data_in_3g,
R.drawable.stat_sys_data_out_3g, R.drawable.stat_sys_data_out_3g,
R.drawable.stat_sys_data_inandout_3g, R.drawable.stat_sys_data_inandout_3g },
{ R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0 }
}; };
private static final int[] sDataNetType_e = new int[] { private static final int[][] sDataNetType_e = {
R.drawable.stat_sys_data_connected_e, { R.drawable.stat_sys_data_connected_e,
R.drawable.stat_sys_data_in_e, R.drawable.stat_sys_data_in_e,
R.drawable.stat_sys_data_out_e, R.drawable.stat_sys_data_out_e,
R.drawable.stat_sys_data_inandout_e, R.drawable.stat_sys_data_inandout_e },
{ R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0 }
}; };
//3.5G //3.5G
private static final int[] sDataNetType_h = new int[] { private static final int[][] sDataNetType_h = {
R.drawable.stat_sys_data_connected_h, { R.drawable.stat_sys_data_connected_h,
R.drawable.stat_sys_data_in_h, R.drawable.stat_sys_data_in_h,
R.drawable.stat_sys_data_out_h, R.drawable.stat_sys_data_out_h,
R.drawable.stat_sys_data_inandout_h, R.drawable.stat_sys_data_inandout_h },
{ R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0 }
}; };
//CDMA //CDMA
// Use 3G icons for EVDO data and 1x icons for 1XRTT data // Use 3G icons for EVDO data and 1x icons for 1XRTT data
private static final int[] sDataNetType_1x = new int[] { private static final int[][] sDataNetType_1x = {
R.drawable.stat_sys_data_connected_1x, { R.drawable.stat_sys_data_connected_1x,
R.drawable.stat_sys_data_in_1x, R.drawable.stat_sys_data_in_1x,
R.drawable.stat_sys_data_out_1x, R.drawable.stat_sys_data_out_1x,
R.drawable.stat_sys_data_inandout_1x, R.drawable.stat_sys_data_inandout_1x },
}; { R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0 }
};
// Assume it's all good unless we hear otherwise. We don't always seem // Assume it's all good unless we hear otherwise. We don't always seem
// to get broadcasts that it *is* there. // to get broadcasts that it *is* there.
@ -292,17 +315,22 @@ public class StatusBarPolicy {
private boolean mBluetoothEnabled; private boolean mBluetoothEnabled;
// wifi // wifi
private static final int[] sWifiSignalImages = new int[] { private static final int[][] sWifiSignalImages = {
R.drawable.stat_sys_wifi_signal_1, { R.drawable.stat_sys_wifi_signal_1,
R.drawable.stat_sys_wifi_signal_2, R.drawable.stat_sys_wifi_signal_2,
R.drawable.stat_sys_wifi_signal_3, R.drawable.stat_sys_wifi_signal_3,
R.drawable.stat_sys_wifi_signal_4, R.drawable.stat_sys_wifi_signal_4 },
{ R.drawable.stat_sys_data_in_e,
R.drawable.stat_sys_data_in_e,
R.drawable.stat_sys_data_in_e,
R.drawable.stat_sys_data_in_e }
}; };
private static final int sWifiTemporarilyNotConnectedImage = private static final int sWifiTemporarilyNotConnectedImage =
R.drawable.stat_sys_wifi_signal_0; R.drawable.stat_sys_wifi_signal_0;
private int mLastWifiSignalLevel = -1; private int mLastWifiSignalLevel = -1;
private boolean mIsWifiConnected = false; private boolean mIsWifiConnected = false;
private int mLastWifiInetConnectivityState = 0;
// sync state // sync state
// If sync is active the SyncActive icon is displayed. If sync is not active but // If sync is active the SyncActive icon is displayed. If sync is not active but
@ -353,6 +381,10 @@ public class StatusBarPolicy {
else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) { else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
updateTTY(intent); updateTTY(intent);
} }
else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
// TODO - stop using other means to get wifi/mobile info
updateConnectivity(intent);
}
} }
}; };
@ -389,7 +421,7 @@ public class StatusBarPolicy {
mService.setIconVisibility("data_connection", false); mService.setIconVisibility("data_connection", false);
// wifi // wifi
mService.setIcon("wifi", sWifiSignalImages[0], 0); mService.setIcon("wifi", sWifiSignalImages[0][0], 0);
mService.setIconVisibility("wifi", false); mService.setIconVisibility("wifi", false);
// wifi will get updated by the sticky intents // wifi will get updated by the sticky intents
@ -456,6 +488,7 @@ public class StatusBarPolicy {
filter.addAction(LocationManager.GPS_FIX_CHANGE_ACTION); filter.addAction(LocationManager.GPS_FIX_CHANGE_ACTION);
filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION); filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
// load config to determine if to distinguish Hspa data icon // load config to determine if to distinguish Hspa data icon
@ -659,6 +692,50 @@ public class StatusBarPolicy {
} }
} }
private void updateConnectivity(Intent intent) {
NetworkInfo info = (NetworkInfo)(intent.getParcelableExtra(
ConnectivityManager.EXTRA_NETWORK_INFO));
int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
Slog.d(TAG, "got CONNECTIVITY_ACTION - info=" + info + ", status = " + connectionStatus);
if (info.isConnected() == false) return;
switch (info.getType()) {
case ConnectivityManager.TYPE_MOBILE:
if (info.isConnected()) {
updateDataNetType(info.getSubtype(), connectionStatus);
updateDataIcon();
}
break;
case ConnectivityManager.TYPE_WIFI:
if (info.isConnected()) {
mIsWifiConnected = true;
mLastWifiInetConnectivityState =
(connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
int iconId;
if (mLastWifiSignalLevel == -1) {
iconId = sWifiSignalImages[mLastWifiInetConnectivityState][0];
} else {
iconId = sWifiSignalImages[mLastWifiInetConnectivityState]
[mLastWifiSignalLevel];
}
mService.setIcon("wifi", iconId, 0);
// Show the icon since wi-fi is connected
mService.setIconVisibility("wifi", true);
} else {
mLastWifiSignalLevel = -1;
mIsWifiConnected = false;
mLastWifiInetConnectivityState = 0;
int iconId = sWifiSignalImages[0][0];
mService.setIcon("wifi", iconId, 0);
// Hide the icon since we're not connected
mService.setIconVisibility("wifi", false);
}
break;
}
}
private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override @Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) { public void onSignalStrengthsChanged(SignalStrength signalStrength) {
@ -686,7 +763,7 @@ public class StatusBarPolicy {
@Override @Override
public void onDataConnectionStateChanged(int state, int networkType) { public void onDataConnectionStateChanged(int state, int networkType) {
mDataState = state; mDataState = state;
updateDataNetType(networkType); updateDataNetType(networkType, 0);
updateDataIcon(); updateDataIcon();
} }
@ -848,37 +925,38 @@ public class StatusBarPolicy {
return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr; return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
} }
private final void updateDataNetType(int net) { private final void updateDataNetType(int net, int inetCondition) {
int connected = (inetCondition > INET_CONDITION_THRESHOLD ? 1 : 0);
switch (net) { switch (net) {
case TelephonyManager.NETWORK_TYPE_EDGE: case TelephonyManager.NETWORK_TYPE_EDGE:
mDataIconList = sDataNetType_e; mDataIconList = sDataNetType_e[connected];
break; break;
case TelephonyManager.NETWORK_TYPE_UMTS: case TelephonyManager.NETWORK_TYPE_UMTS:
mDataIconList = sDataNetType_3g; mDataIconList = sDataNetType_3g[connected];
break; break;
case TelephonyManager.NETWORK_TYPE_HSDPA: case TelephonyManager.NETWORK_TYPE_HSDPA:
case TelephonyManager.NETWORK_TYPE_HSUPA: case TelephonyManager.NETWORK_TYPE_HSUPA:
case TelephonyManager.NETWORK_TYPE_HSPA: case TelephonyManager.NETWORK_TYPE_HSPA:
if (mHspaDataDistinguishable) { if (mHspaDataDistinguishable) {
mDataIconList = sDataNetType_h; mDataIconList = sDataNetType_h[connected];
} else { } else {
mDataIconList = sDataNetType_3g; mDataIconList = sDataNetType_3g[connected];
} }
break; break;
case TelephonyManager.NETWORK_TYPE_CDMA: case TelephonyManager.NETWORK_TYPE_CDMA:
// display 1xRTT for IS95A/B // display 1xRTT for IS95A/B
mDataIconList = this.sDataNetType_1x; mDataIconList = sDataNetType_1x[connected];
break; break;
case TelephonyManager.NETWORK_TYPE_1xRTT: case TelephonyManager.NETWORK_TYPE_1xRTT:
mDataIconList = this.sDataNetType_1x; mDataIconList = sDataNetType_1x[connected];
break; break;
case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
case TelephonyManager.NETWORK_TYPE_EVDO_A: case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_EVDO_B: case TelephonyManager.NETWORK_TYPE_EVDO_B:
mDataIconList = sDataNetType_3g; mDataIconList = sDataNetType_3g[connected];
break; break;
default: default:
mDataIconList = sDataNetType_g; mDataIconList = sDataNetType_g[connected];
break; break;
} }
} }
@ -1019,34 +1097,6 @@ public class StatusBarPolicy {
if (!enabled) { if (!enabled) {
mService.setIconVisibility("wifi", false); mService.setIconVisibility("wifi", false);
} }
} else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
final NetworkInfo networkInfo = (NetworkInfo)
intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
int iconId;
if (networkInfo != null && networkInfo.isConnected()) {
mIsWifiConnected = true;
if (mLastWifiSignalLevel == -1) {
iconId = sWifiSignalImages[0];
} else {
iconId = sWifiSignalImages[mLastWifiSignalLevel];
}
mService.setIcon("wifi", iconId, 0);
// Show the icon since wi-fi is connected
mService.setIconVisibility("wifi", true);
} else {
mLastWifiSignalLevel = -1;
mIsWifiConnected = false;
iconId = sWifiSignalImages[0];
mService.setIcon("wifi", iconId, 0);
// Hide the icon since we're not connected
mService.setIconVisibility("wifi", false);
}
} else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
int iconId; int iconId;
final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200); final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
@ -1055,7 +1105,7 @@ public class StatusBarPolicy {
if (newSignalLevel != mLastWifiSignalLevel) { if (newSignalLevel != mLastWifiSignalLevel) {
mLastWifiSignalLevel = newSignalLevel; mLastWifiSignalLevel = newSignalLevel;
if (mIsWifiConnected) { if (mIsWifiConnected) {
iconId = sWifiSignalImages[newSignalLevel]; iconId = sWifiSignalImages[mLastWifiInetConnectivityState][newSignalLevel];
} else { } else {
iconId = sWifiTemporarilyNotConnectedImage; iconId = sWifiTemporarilyNotConnectedImage;
} }

View File

@ -92,6 +92,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private Context mContext; private Context mContext;
private int mNetworkPreference; private int mNetworkPreference;
private int mActiveDefaultNetwork = -1; private int mActiveDefaultNetwork = -1;
// 0 is full bad, 100 is full good
private int mDefaultInetCondition = 0;
private int mDefaultInetConditionPublished = 0;
private boolean mInetConditionChangeInFlight = false;
private int mDefaultConnectionSequence = 0;
private int mNumDnsEntries; private int mNumDnsEntries;
@ -1047,6 +1052,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
info.getExtraInfo()); info.getExtraInfo());
} }
intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
sendStickyBroadcast(intent); sendStickyBroadcast(intent);
} }
@ -1165,6 +1171,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
} }
} }
mActiveDefaultNetwork = type; mActiveDefaultNetwork = type;
// this will cause us to come up initially as unconnected and switching
// to connected after our normal pause unless somebody reports us as reall
// disconnected
mDefaultInetConditionPublished = 0;
mDefaultConnectionSequence++;
mInetConditionChangeInFlight = false;
// Don't do this - if we never sign in stay, grey
//reportNetworkCondition(mActiveDefaultNetwork, 100);
} }
thisNet.setTeardownRequested(false); thisNet.setTeardownRequested(false);
thisNet.updateNetworkSettings(); thisNet.updateNetworkSettings();
@ -1467,6 +1481,70 @@ public class ConnectivityService extends IConnectivityManager.Stub {
FeatureUser u = (FeatureUser)msg.obj; FeatureUser u = (FeatureUser)msg.obj;
u.expire(); u.expire();
break; break;
case NetworkStateTracker.EVENT_INET_CONDITION_CHANGE:
if (DBG) {
Slog.d(TAG, "Inet connectivity change, net=" +
msg.arg1 + ", condition=" + msg.arg2 +
",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
}
if (mActiveDefaultNetwork == -1) {
if (DBG) Slog.d(TAG, "no active default network - aborting");
break;
}
if (mActiveDefaultNetwork != msg.arg1) {
if (DBG) Slog.d(TAG, "given net not default - aborting");
break;
}
mDefaultInetCondition = msg.arg2;
int delay;
if (mInetConditionChangeInFlight == false) {
if (DBG) Slog.d(TAG, "starting a change hold");
// setup a new hold to debounce this
if (mDefaultInetCondition > 50) {
delay = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
} else {
delay = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000);
}
mInetConditionChangeInFlight = true;
sendMessageDelayed(obtainMessage(
NetworkStateTracker.EVENT_INET_CONDITION_HOLD_END,
mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
} else {
// we've set the new condition, when this hold ends that will get
// picked up
if (DBG) Slog.d(TAG, "currently in hold - not setting new end evt");
}
break;
case NetworkStateTracker.EVENT_INET_CONDITION_HOLD_END:
if (DBG) {
Slog.d(TAG, "Inet hold end, net=" + msg.arg1 +
", condition =" + mDefaultInetCondition +
", published condition =" + mDefaultInetConditionPublished);
}
mInetConditionChangeInFlight = false;
if (mActiveDefaultNetwork == -1) {
if (DBG) Slog.d(TAG, "no active default network - aborting");
break;
}
if (mDefaultConnectionSequence != msg.arg2) {
if (DBG) Slog.d(TAG, "event hold for obsolete network - aborting");
break;
}
if (mDefaultInetConditionPublished == mDefaultInetCondition) {
if (DBG) Slog.d(TAG, "no change in condition - aborting");
break;
}
NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
if (networkInfo.isConnected() == false) {
if (DBG) Slog.d(TAG, "default network not connected - aborting");
break;
}
mDefaultInetConditionPublished = mDefaultInetCondition;
sendConnectedBroadcast(networkInfo);
break;
} }
} }
} }
@ -1550,4 +1628,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0); Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
return tetherEnabledInSettings && mTetheringConfigValid; return tetherEnabledInSettings && mTetheringConfigValid;
} }
// 100 percent is full good, 0 is full bad.
public void reportInetCondition(int networkType, int percentage) {
if (DBG) Slog.d(TAG, "reportNetworkCondition(" + networkType + ", " + percentage + ")");
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.STATUS_BAR,
"ConnectivityService");
mHandler.sendMessage(mHandler.obtainMessage(
NetworkStateTracker.EVENT_INET_CONDITION_CHANGE, networkType, percentage));
}
} }