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 P2pMonitor(BuiltInPrintService service)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} */ toString(WifiP2pDevice device)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 statusString(int status)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 */ discover(P2pPeerListener listener)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 */ stopDiscover(P2pPeerListener listener)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 */ connect(WifiP2pDevice peer, P2pConnectionListener listener)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 */ stopConnect(P2pConnectionListener listener)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 */ getConnection()174 P2pConnectionProcedure getConnection() { 175 return mConnection; 176 } 177 178 /** Return the current connected interface, if any */ getConnectedInterface()179 public String getConnectedInterface() { 180 return mConnectedInterface; 181 } 182 183 /** Forcibly stops all connections/discoveries in progress, if any */ stopAll()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