Home | History | Annotate | Download | only in p2p
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.bips.p2p;
     18 
     19 import android.content.BroadcastReceiver;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.net.wifi.p2p.WifiP2pDevice;
     23 import android.net.wifi.p2p.WifiP2pDeviceList;
     24 import android.net.wifi.p2p.WifiP2pManager;
     25 import android.os.Looper;
     26 import android.util.Log;
     27 
     28 import com.android.bips.BuiltInPrintService;
     29 import com.android.bips.util.BroadcastMonitor;
     30 
     31 import java.util.ArrayList;
     32 import java.util.Collection;
     33 import java.util.HashSet;
     34 import java.util.List;
     35 import java.util.Set;
     36 import java.util.concurrent.CopyOnWriteArrayList;
     37 import java.util.regex.Pattern;
     38 
     39 /**
     40  * Manage the process of discovering P2P printer devices
     41  */
     42 class P2pDiscoveryProcedure {
     43     private static final String TAG = P2pDiscoveryProcedure.class.getSimpleName();
     44     private static final boolean DEBUG = false;
     45 
     46     private static final Pattern PRINTER_PATTERN =
     47             Pattern.compile("^(^3-.+-[145])|(0003.+000[145])$");
     48 
     49     private final WifiP2pManager mP2pManager;
     50     private final List<P2pPeerListener> mListeners = new CopyOnWriteArrayList<>();
     51     private final List<WifiP2pDevice> mPeers = new ArrayList<>();
     52     private BroadcastMonitor mBroadcastMonitor;
     53     private WifiP2pManager.Channel mChannel;
     54 
     55     P2pDiscoveryProcedure(BuiltInPrintService service, WifiP2pManager p2pManager,
     56             P2pPeerListener listener) {
     57         mP2pManager = p2pManager;
     58         if (DEBUG) Log.d(TAG, "P2pDiscoveryProcedure()");
     59         mChannel = mP2pManager.initialize(service, Looper.getMainLooper(), null);
     60         mListeners.add(listener);
     61 
     62         BroadcastReceiver receiver = new BroadcastReceiver() {
     63             @Override
     64             public void onReceive(Context context, Intent intent) {
     65                 String action = intent.getAction();
     66                 if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
     67                     int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
     68                     boolean isP2pEnabled = state == WifiP2pManager.WIFI_P2P_STATE_ENABLED;
     69                     if (DEBUG) Log.d(TAG, "WIFI_P2P_STATE_CHANGED_ACTION: enabled=" + isP2pEnabled);
     70                     if (isP2pEnabled) {
     71                         mP2pManager.stopPeerDiscovery(mChannel, null);
     72                         mP2pManager.discoverPeers(mChannel, null);
     73                     }
     74                 } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
     75                     WifiP2pDeviceList list = intent.getParcelableExtra(
     76                             WifiP2pManager.EXTRA_P2P_DEVICE_LIST);
     77                     Collection<WifiP2pDevice> newPeers = list.getDeviceList();
     78                     updatePeers(newPeers);
     79 
     80                     if (newPeers.isEmpty()) {
     81                         // Remind system we are still interested
     82                         mP2pManager.stopPeerDiscovery(mChannel, null);
     83                         mP2pManager.discoverPeers(mChannel, null);
     84                     }
     85                 }
     86             }
     87         };
     88 
     89         mBroadcastMonitor = service.receiveBroadcasts(receiver,
     90                 WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION,
     91                 WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
     92         mP2pManager.discoverPeers(mChannel, null);
     93     }
     94 
     95     void addListener(P2pPeerListener listener) {
     96         mListeners.add(listener);
     97         if (!mPeers.isEmpty()) {
     98             for (WifiP2pDevice peer : mPeers) {
     99                 listener.onPeerFound(peer);
    100             }
    101         }
    102     }
    103 
    104     void removeListener(P2pPeerListener listener) {
    105         mListeners.remove(listener);
    106     }
    107 
    108     List<P2pPeerListener> getListeners() {
    109         return mListeners;
    110     }
    111 
    112     /**
    113      * Signal find/loss of each device to listeners as it occurs
    114      */
    115     private void updatePeers(Collection<WifiP2pDevice> newPeers) {
    116         List<WifiP2pDevice> oldPeers = new ArrayList<>(mPeers);
    117 
    118         // Reset peer list and populate with new printer-type devices
    119         mPeers.clear();
    120         for (WifiP2pDevice peer : newPeers) {
    121             if (PRINTER_PATTERN.matcher(peer.primaryDeviceType).find()) {
    122                 mPeers.add(peer);
    123             }
    124         }
    125 
    126         // Notify newly found devices
    127         Set<String> foundAddresses = new HashSet<>();
    128         for (WifiP2pDevice peer : mPeers) {
    129             foundAddresses.add(peer.deviceAddress);
    130             WifiP2pDevice old = getDevice(oldPeers, peer.deviceAddress);
    131             if (old == null || !old.equals(peer)) {
    132                 for (P2pPeerListener listener : mListeners) {
    133                     listener.onPeerFound(peer);
    134                 }
    135             }
    136         }
    137 
    138         // Notify lost devices
    139         for (WifiP2pDevice oldPeer : oldPeers) {
    140             if (!foundAddresses.contains(oldPeer.deviceAddress)) {
    141                 for (P2pPeerListener listener : mListeners) {
    142                     listener.onPeerLost(oldPeer);
    143                 }
    144             }
    145         }
    146     }
    147 
    148     private WifiP2pDevice getDevice(Collection<WifiP2pDevice> peers, String address) {
    149         for (WifiP2pDevice found : peers) {
    150             if (found.deviceAddress.equals(address)) {
    151                 return found;
    152             }
    153         }
    154         return null;
    155     }
    156 
    157     /** Stop the discovery procedure */
    158     public void cancel() {
    159         if (DEBUG) Log.d(TAG, "stop()");
    160         mBroadcastMonitor.close();
    161         if (mChannel != null) {
    162             mP2pManager.stopPeerDiscovery(mChannel, null);
    163             mChannel.close();
    164             mChannel = null;
    165         }
    166     }
    167 }
    168