/* * Copyright (C) 2017 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.bips.p2p; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.wifi.p2p.WifiP2pDevice; import android.net.wifi.p2p.WifiP2pDeviceList; import android.net.wifi.p2p.WifiP2pManager; import android.os.Looper; import android.util.Log; import com.android.bips.BuiltInPrintService; import com.android.bips.util.BroadcastMonitor; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.regex.Pattern; /** * Manage the process of discovering P2P printer devices */ class P2pDiscoveryProcedure { private static final String TAG = P2pDiscoveryProcedure.class.getSimpleName(); private static final boolean DEBUG = false; private static final Pattern PRINTER_PATTERN = Pattern.compile("^(^3-.+-[145])|(0003.+000[145])$"); private final WifiP2pManager mP2pManager; private final List mListeners = new CopyOnWriteArrayList<>(); private final List mPeers = new ArrayList<>(); private BroadcastMonitor mBroadcastMonitor; private WifiP2pManager.Channel mChannel; P2pDiscoveryProcedure(BuiltInPrintService service, WifiP2pManager p2pManager, P2pPeerListener listener) { mP2pManager = p2pManager; if (DEBUG) Log.d(TAG, "P2pDiscoveryProcedure()"); mChannel = mP2pManager.initialize(service, Looper.getMainLooper(), null); mListeners.add(listener); BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) { int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1); boolean isP2pEnabled = state == WifiP2pManager.WIFI_P2P_STATE_ENABLED; if (DEBUG) Log.d(TAG, "WIFI_P2P_STATE_CHANGED_ACTION: enabled=" + isP2pEnabled); if (isP2pEnabled) { mP2pManager.stopPeerDiscovery(mChannel, null); mP2pManager.discoverPeers(mChannel, null); } } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) { WifiP2pDeviceList list = intent.getParcelableExtra( WifiP2pManager.EXTRA_P2P_DEVICE_LIST); Collection newPeers = list.getDeviceList(); updatePeers(newPeers); if (newPeers.isEmpty()) { // Remind system we are still interested mP2pManager.stopPeerDiscovery(mChannel, null); mP2pManager.discoverPeers(mChannel, null); } } } }; mBroadcastMonitor = service.receiveBroadcasts(receiver, WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION, WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); mP2pManager.discoverPeers(mChannel, null); } void addListener(P2pPeerListener listener) { mListeners.add(listener); if (!mPeers.isEmpty()) { for (WifiP2pDevice peer : mPeers) { listener.onPeerFound(peer); } } } void removeListener(P2pPeerListener listener) { mListeners.remove(listener); } List getListeners() { return mListeners; } /** * Signal find/loss of each device to listeners as it occurs */ private void updatePeers(Collection newPeers) { List oldPeers = new ArrayList<>(mPeers); // Reset peer list and populate with new printer-type devices mPeers.clear(); for (WifiP2pDevice peer : newPeers) { if (PRINTER_PATTERN.matcher(peer.primaryDeviceType).find()) { mPeers.add(peer); } } // Notify newly found devices Set foundAddresses = new HashSet<>(); for (WifiP2pDevice peer : mPeers) { foundAddresses.add(peer.deviceAddress); WifiP2pDevice old = getDevice(oldPeers, peer.deviceAddress); if (old == null || !old.equals(peer)) { for (P2pPeerListener listener : mListeners) { listener.onPeerFound(peer); } } } // Notify lost devices for (WifiP2pDevice oldPeer : oldPeers) { if (!foundAddresses.contains(oldPeer.deviceAddress)) { for (P2pPeerListener listener : mListeners) { listener.onPeerLost(oldPeer); } } } } private WifiP2pDevice getDevice(Collection peers, String address) { for (WifiP2pDevice found : peers) { if (found.deviceAddress.equals(address)) { return found; } } return null; } /** Stop the discovery procedure */ public void cancel() { if (DEBUG) Log.d(TAG, "stop()"); mBroadcastMonitor.close(); if (mChannel != null) { mP2pManager.stopPeerDiscovery(mChannel, null); mChannel.close(); mChannel = null; } } }