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.Context;
     20 import android.net.wifi.p2p.WifiP2pDevice;
     21 import android.net.wifi.p2p.WifiP2pInfo;
     22 import android.net.wifi.p2p.WifiP2pManager;
     23 import android.util.Log;
     24 
     25 import com.android.bips.BuiltInPrintService;
     26 
     27 /**
     28  * Globally manage P2P discovery and connectivity
     29  */
     30 public class P2pMonitor {
     31     private static final String TAG = P2pMonitor.class.getSimpleName();
     32     private static final boolean DEBUG = false;
     33 
     34     private final BuiltInPrintService mService;
     35     private final WifiP2pManager mP2pManager;
     36     private P2pDiscoveryProcedure mPeerDiscovery;
     37     private P2pConnectionProcedure mConnection;
     38     private String mConnectedInterface;
     39 
     40     public P2pMonitor(BuiltInPrintService service) {
     41         mService = service;
     42         mP2pManager = (WifiP2pManager) mService.getSystemService(Context.WIFI_P2P_SERVICE);
     43     }
     44 
     45     /** Return a printable String form of a {@link WifiP2pDevice} */
     46     public static String toString(WifiP2pDevice device) {
     47         if (device == null) {
     48             return "null";
     49         } else {
     50             return device.deviceName + " " + device.deviceAddress + ", status="
     51                     + statusString(device.status);
     52         }
     53     }
     54 
     55     private static String statusString(int status) {
     56         switch (status) {
     57             case WifiP2pDevice.AVAILABLE:
     58                 return "available";
     59             case WifiP2pDevice.CONNECTED:
     60                 return "connected";
     61             case WifiP2pDevice.FAILED:
     62                 return "failed";
     63             case WifiP2pDevice.INVITED:
     64                 return "invited";
     65             case WifiP2pDevice.UNAVAILABLE:
     66                 return "unavailable";
     67             default:
     68                 return "unknown";
     69         }
     70     }
     71 
     72     /**
     73      * Start a discovery of Wi-Fi Direct peers until all requests are closed
     74      */
     75     public void discover(P2pPeerListener listener) {
     76         if (DEBUG) Log.d(TAG, "discover()");
     77 
     78         if (mP2pManager == null) {
     79             return;
     80         }
     81         if (mPeerDiscovery == null) {
     82             mPeerDiscovery = new P2pDiscoveryProcedure(mService, mP2pManager, listener);
     83         } else {
     84             mPeerDiscovery.addListener(listener);
     85         }
     86     }
     87 
     88     /**
     89      * Remove the request to discover having the same listener. When all outstanding requests are
     90      * removed, discovery itself is stopped.
     91      */
     92     public void stopDiscover(P2pPeerListener listener) {
     93         if (DEBUG) Log.d(TAG, "stopDiscover");
     94         if (mPeerDiscovery != null) {
     95             mPeerDiscovery.removeListener(listener);
     96             if (mPeerDiscovery.getListeners().isEmpty()) {
     97                 mPeerDiscovery.cancel();
     98                 mPeerDiscovery = null;
     99             }
    100         }
    101     }
    102 
    103     /**
    104      * Request connection to a peer (which may already be connected) at least until stopped. Keeps
    105      * the current connection open as long as it might be useful.
    106      */
    107     public void connect(WifiP2pDevice peer, P2pConnectionListener listener) {
    108         if (DEBUG) Log.d(TAG, "connect(" + toString(peer) + ")");
    109 
    110         if (mP2pManager == null) {
    111             // Device has no P2P support so indicate failure
    112             mService.getMainHandler().post(listener::onConnectionClosed);
    113             return;
    114         }
    115 
    116         // Check for competing connection
    117         if (mConnection != null && !peer.deviceAddress.equals(mConnection.getPeer()
    118                 .deviceAddress)) {
    119             if (mConnection.getListenerCount() == 1) {
    120                 // The only listener is our internal one, so close this connection to make room
    121                 mConnection.close();
    122                 mConnection = null;
    123             } else {
    124                 // Cannot open connection
    125                 mService.getMainHandler().post(listener::onConnectionClosed);
    126                 return;
    127             }
    128         }
    129 
    130         // Check for existing connection to the same device
    131         if (mConnection == null) {
    132             // Create a new connection request with our internal listener
    133             mConnection = new P2pConnectionProcedure(mService, mP2pManager, peer,
    134                     new P2pConnectionListener() {
    135                         @Override
    136                         public void onConnectionOpen(String networkInterface, WifiP2pInfo info) {
    137                             mConnectedInterface = networkInterface;
    138                         }
    139 
    140                         @Override
    141                         public void onConnectionClosed() {
    142                             mConnectedInterface = null;
    143                         }
    144 
    145                         @Override
    146                         public void onConnectionDelayed(boolean delayed) {
    147                         }
    148                     });
    149         }
    150         mConnection.addListener(listener);
    151     }
    152 
    153     /**
    154      * Give up on the connection request associated with a listener. The connection will stay
    155      * open as long as other requests exist.
    156      */
    157     void stopConnect(P2pConnectionListener listener) {
    158         if (mConnection == null || !mConnection.hasListener(listener)) {
    159             return;
    160         }
    161 
    162         if (DEBUG) Log.d(TAG, "stopConnect " + toString(mConnection.getPeer()));
    163         mConnection.removeListener(listener);
    164 
    165         // If current connection attempt is incomplete and no longer required, close it.
    166         if (mConnection.getListenerCount() == 1 && mConnectedInterface == null) {
    167             if (DEBUG) Log.d(TAG, "Abandoning connection request");
    168             mConnection.close();
    169             mConnection = null;
    170         }
    171     }
    172 
    173     /** Return the current connection procedure, if any */
    174     P2pConnectionProcedure getConnection() {
    175         return mConnection;
    176     }
    177 
    178     /** Return the current connected interface, if any */
    179     public String getConnectedInterface() {
    180         return mConnectedInterface;
    181     }
    182 
    183     /** Forcibly stops all connections/discoveries in progress, if any */
    184     public void stopAll() {
    185         if (mConnection != null) {
    186             mConnection.close();
    187             mConnection = null;
    188             mConnectedInterface = null;
    189         }
    190         if (mPeerDiscovery != null) {
    191             mPeerDiscovery.cancel();
    192             mPeerDiscovery = null;
    193         }
    194     }
    195 }
    196