如何在Wi-Fi Direct范围内不再提供对等设备时收到通知?

Raf*_*ael 14 android wifimanager android-wifi wifi-direct wifip2p

我正在开发基于使用Wifi Direct API 的Android应用程序.我已在我的Activitya BroadcastReceiver中注册,以便收到有关以下Wifi Direct事件的通知:

WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION 
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION 
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION  
WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
Run Code Online (Sandbox Code Playgroud)

我相信对等列表中的任何更改(包含或排除Wifi Direct范围内的对等点)都可能触发BroadcastReceiver.在我的应用中,当找到新的对等体时,其名称正确地包含在a中ListView,但如果对等体离开无线范围(或者如果我关闭其Wi-Fi接口),BroadcastReceiver则不会调用(更具体地说,

WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION
Run Code Online (Sandbox Code Playgroud)

事件未被触发),并且对等名称保留在ListView.

我想知道是否有任何方式来处理这个问题,因为对等名称包含在中ListView,但从未排除.我已经考虑重新初始化Channel和WifiP2pManager实例,但我相信这会断开所有同行.

Vik*_*ram 25

我相信对等列表中的任何更改(包含或排除Wifi Direct范围内的对等方)都可能触发BroadcastReceiver.

是的,我认为这应该发生.

在我的应用程序中,当找到新的对等体时,其名称正确地包含在ListView中,但如果对等体离开无线范围(或者如果我关闭其Wi-Fi接口),则不调用BroadcastReceiver(更具体地说, WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION事件未被触发),对等名称仍保留在ListView中.

我们可以尝试挖掘源代码,看看我们是否可以解释这种行为.

注意:我没有提供解决方案.但是,以下研究可能会帮助您更好地理解"问题".

我们将从这里开始:WifiP2pSettings 链接

这是您在转到设置> Wifi> Wifi-Direct时看到的片段.如果您浏览代码,您会注意到实现与WifiDirectDemo项目非常相似- BroadcastReceiver侦听相同的四个操作(以及另外两个 - 一个用于UI更新).我们看这个片段的原因是检查演示本身是否有缺陷.但是,看起来演示没问题.

继续 - 让我们看看谁在广播这个动作WIFI_P2P_PEERS_CHANGED_ACTION- 最终,我们有兴趣找到一旦设备离线/超出范围就不会发生这种情况的原因.这将我们带到WifiP2pService Link.

该方法WifiP2pService # sendPeersChangedBroadcast()发布广播:

private void sendPeersChangedBroadcast() {
    final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
    intent.putExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST, new WifiP2pDeviceList(mPeers));
    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
}
Run Code Online (Sandbox Code Playgroud)

从查看中WifiP2pService,您可以看出sendPeersChangedBroadcast()响应多个事件而调用它.我们对此感兴趣:WifiMonitor.P2P_DEVICE_LOST_EVENT 链接:

....
case WifiMonitor.P2P_DEVICE_LOST_EVENT:
    device = (WifiP2pDevice) message.obj;
    // Gets current details for the one removed
    device = mPeers.remove(device.deviceAddress);
    if (device != null) {
        sendPeersChangedBroadcast();
    }
    break;
....
Run Code Online (Sandbox Code Playgroud)

WifiMonitor # handleP2pEvents(String)负责发送上述消息case.上链找到MonitorThread- 一个静态的内部类WifiMonitor.MonitorThread # dispatchEvent(String)调用handleP2pEvents(String)方法.

最后,有趣的事情.看看run()方法MonitorThread:

private static class MonitorThread extends Thread {

    ....

    public void run() {
        //noinspection InfiniteLoopStatement
        for (;;) {
            String eventStr = mWifiNative.waitForEvent();
            ....
        }
    }

    ....
}            
Run Code Online (Sandbox Code Playgroud)
  • 首先,我们在无限循环中.
  • 第二,mWifiNative.waitForEvent()告诉我它可能是一个阻塞的电话.

这两点合起来向我表明,我不会得到一个明确的反应 - 好吧,绝对没有'瞬间'.我们通过上升链到达的方法MonitorThread # dispatchEvent(String)- 从这个无限循环内部调用.

让我们检查一下是否可以支持我们有根据的猜测:

看看LinkWifiNative类,特别是方法.从Link类调用此方法.通过方法:setScanInterval(int)WifiStateMachine processMessage(Message)

....
case WifiP2pService.P2P_CONNECTION_CHANGED:
    NetworkInfo info = (NetworkInfo) message.obj;
    mP2pConnected.set(info.isConnected());
    if (mP2pConnected.get()) {
        int defaultInterval = mContext.getResources().getInteger(
                            R.integer.config_wifi_scan_interval_p2p_connected);
        long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
                            Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
                            defaultInterval);

        // ====>> Interval defined here
        mWifiNative.setScanInterval((int) scanIntervalMs/1000);
    } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) {
        if (DBG) log("Turn on scanning after p2p disconnected");
            sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
                            ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
    }
....
Run Code Online (Sandbox Code Playgroud)

请注意defaultInterval第一个if block.它正在请求链接中R.integer.config_wifi_scan_interval_p2p_connected定义的:config.xml

<!-- Integer indicating wpa_supplicant scan interval when p2p is connected in milliseconds -->
<integer translatable="false" name="config_wifi_scan_interval_p2p_connected">60000</integer>
Run Code Online (Sandbox Code Playgroud)

60000毫秒 那是1分钟.因此,如果Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS未设置,则扫描间隔1分钟.

因为,WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS在全球设置下,我们无法改变它.事实上,它甚至无法阅读.意思是,我们在这里唯一的保证是同行列表在一分钟内刷新.间隔当然可以因品牌而异.

为了验证这一点,我在华硕平板电脑和戴尔平板电脑上运行了演示.就像你说的那样,设备上线的速度相当快(在发现阶段).在关闭wifi时,我响应了响应.离线设备自动从列表中删除- 大幅延迟.戴尔平板电脑接近60 seconds注意到华硕离线了.华硕另一方面拿走了45 seconds.

对我来说,这似乎是由android强制执行的限制.我不知道为什么.我希望这里有人可以为您提供解决方案 - 可能会进行此项研究并进一步探索.但如果不存在解决方案(目前),我不会感到惊讶.