Android - 为什么ConnectivityManager.isActiveNetworkMetered总是返回true(即使在Wifi上)

时间:2014-05-26 20:44:05

标签: android wifi android-wifi

在我的Android音乐流媒体应用中,下面的代码路径有助于根据ConnectivityManager类实例返回的值在高比特率流与较低比特率之间做出决定。

我试图理解为什么ConnectivityManager.isActiveNetworkMetered()会返回“true”,这显然是我在本地Wifi网络上。请使用以下Android / Java代码:

boolean isMetered = false;
boolean isWifi = false;
boolean isEthernet = false;
boolean isRoaming = false;
boolean isConnected = false;

NetworkInfo netinfo = connManager.getActiveNetworkInfo();
if (netinfo != null)
{
    isWifi = (netinfo.getType() == ConnectivityManager.TYPE_WIFI);
    isEthernet = (netinfo.getType() == ConnectivityManager.TYPE_ETHERNET);
    isRoaming = netinfo.isRoaming();
    isConnected = netinfo.isConnected();

    Log.d(TAG, "active network type = " + netinfo.getTypeName());
    Log.d(TAG, "active network subtype = " + netinfo.getSubtypeName());


    Log.d(TAG, "isConnected = " + isConnected);
    Log.d(TAG, "isWifi = " + isWifi);
    Log.d(TAG, "isEthernet = " + isEthernet);
    Log.d(TAG, "isRoaming = " + isRoaming);
}

// isActiveNetworkMetered was introduced in API 16 (Jelly Bean)
if (android.os.Build.VERSION.SDK_INT >= 16)
{
    isMetered = connManager.isActiveNetworkMetered();
    Log.d(TAG, "isMetered = " + isMetered);
}

当我关闭Wifi并且我唯一的连接是AT& T的LTE网络时,它将以下内容打印到日志控制台:

active network type = mobile
active network subtype = LTE
isConnected = true
isWifi = false
isEthernet = false
isRoaming = false
isMetered = true

以上所有内容都符合预期 - 我正在计量的移动运营商网络上。

现在切换到我的家庭Wifi,同样的代码块打印出来:

active network type = WIFI
active network subtype = 
isConnected = true
isWifi = true
isEthernet = false
isRoaming = false
isMetered = true

为什么isMetered isActiveNetworkMetered的结果仍然显示为 true ?这导致以下代码路径支持较低比特率的流,即使我在我的家庭wifi网络上:

if ((isWifi || isEthernet) && !isMetered)
{
    result = BITRATE_HIGH_KBIT_SEC;
}
else
{
    result = BITRATE_LOW_KBIT_SEC;
}

isActiveNetworkMetered()如何决定网络是否计量?这是WIFI协商的一部分还是SSID广播中的一部分? Android上的网络设置?我在Android Kitkat设备上找不到任何设置,让我可以切换或发现计量网络的设置。

上周我的ISP(Frontier)发给我一个新的Wifi路由器。可能相关?对于这样的设置,我没有在路由器的固件页面上看到任何内容。

我将在今天晚些时候开始工作,看看它在另一个网络上的表现如何。在任何情况下,我都可能编辑上面的代码以跳过计量检查,除非我能在某处证明它只是一个不正确的设置。

更新 - 我的HTC One M8手机(运行Kitkat)总是返回计量网络的问题,但2012年我的Nexus 7没有(也升级到Android 4.4 Kitkat)。

问题已解决 - 事实证明我的Wifi被我的手机标记为“移动热点”。有关如何查找和切换此标志的更多详细信息是here

1 个答案:

答案 0 :(得分:14)

我也测试了这个,但我观察到了“预期的”结果:WiFi为假,3G为真。这是在Android 4.4.2的Nexus 4中。

奇怪的是,支持库中的ConnectivityManagerCompat class 为WiFi返回false。

final int type = info.getType();
switch (type) {
    case TYPE_MOBILE:
        return true;
    case TYPE_WIFI:
        return false;
    default:
        // err on side of caution
        return true;
}

编辑 - 发现它(我认为)

NetworkPolicyManagerService似乎是最终为此方法生成结果的类。根据它,确实可以计量WiFi连接。它包含一个BroadcastReceiver,“监听wifi状态更改以捕获计量提示”(第567行)。此信息来自NetworkInfo.getMeteredHint(),经过仔细检查后,其中包含此有趣的评论:

/**
 * Flag indicating that AP has hinted that upstream connection is metered,
 * and sensitive to heavy data transfers.
 */
private boolean mMeteredHint;

此标志从DhcpResults.hasMeteredHint()

加载
/**
 * Test if this DHCP lease includes vendor hint that network link is
 * metered, and sensitive to heavy data transfers.
 */
public boolean hasMeteredHint() {
    if (vendorInfo != null) {
        return vendorInfo.contains("ANDROID_METERED");
    } else {
        return false;
    }
}

所以看来,AP确实可以通过使用此标志通知其WiFi客户端计量基础互联网连接。

编辑#2 来自http://www.lorier.net/docs/android-metered

的相关信息
  

当Android手机正在使用另一个Android手机的热点时,它   知道它是在“计量连接”上,因此禁用了   昂贵的同步选项(例如:照片同步)。怎么知道这个?该   android hotspot发送DHCP Option 43(Vendor specific options)   值ANDROID_METERED。客户端,如果它看到ANDROID_METERED   在选项43值的任何地方,打开“昂贵的数据   连接“选项。

看起来这个标志被添加到另一个Android设备提供的热点“玩得很好”。

编辑#3 commit that introduced this feature

  

连接针对Wi-Fi网络的计量DHCP提示。

     

当DHCP租约包含指示远程Wi-Fi的供应商信息时   网络计量,建议NetworkPolicy。用户仍然可以手动   更改“设置”中的计量标志。

您可以通过以下方式访问此设置:

  

设置 - >数据使用 - > (溢出菜单) - >移动热点