| /* |
| * 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.Context; |
| import android.net.wifi.p2p.WifiP2pDevice; |
| import android.net.wifi.p2p.WifiP2pInfo; |
| import android.net.wifi.p2p.WifiP2pManager; |
| import android.util.Log; |
| |
| import com.android.bips.BuiltInPrintService; |
| |
| /** |
| * Globally manage P2P discovery and connectivity |
| */ |
| public class P2pMonitor { |
| private static final String TAG = P2pMonitor.class.getSimpleName(); |
| private static final boolean DEBUG = false; |
| |
| private final BuiltInPrintService mService; |
| private final WifiP2pManager mP2pManager; |
| private P2pDiscoveryProcedure mPeerDiscovery; |
| private P2pConnectionProcedure mConnection; |
| private String mConnectedInterface; |
| |
| public P2pMonitor(BuiltInPrintService service) { |
| mService = service; |
| mP2pManager = (WifiP2pManager) mService.getSystemService(Context.WIFI_P2P_SERVICE); |
| } |
| |
| /** Return a printable String form of a {@link WifiP2pDevice} */ |
| public static String toString(WifiP2pDevice device) { |
| if (device == null) { |
| return "null"; |
| } else { |
| return device.deviceName + " " + device.deviceAddress + ", status=" |
| + statusString(device.status); |
| } |
| } |
| |
| private static String statusString(int status) { |
| switch (status) { |
| case WifiP2pDevice.AVAILABLE: |
| return "available"; |
| case WifiP2pDevice.CONNECTED: |
| return "connected"; |
| case WifiP2pDevice.FAILED: |
| return "failed"; |
| case WifiP2pDevice.INVITED: |
| return "invited"; |
| case WifiP2pDevice.UNAVAILABLE: |
| return "unavailable"; |
| default: |
| return "unknown"; |
| } |
| } |
| |
| /** |
| * Start a discovery of Wi-Fi Direct peers until all requests are closed |
| */ |
| public void discover(P2pPeerListener listener) { |
| if (DEBUG) Log.d(TAG, "discover()"); |
| |
| if (mP2pManager == null) { |
| return; |
| } |
| if (mPeerDiscovery == null) { |
| mPeerDiscovery = new P2pDiscoveryProcedure(mService, mP2pManager, listener); |
| } else { |
| mPeerDiscovery.addListener(listener); |
| } |
| } |
| |
| /** |
| * Remove the request to discover having the same listener. When all outstanding requests are |
| * removed, discovery itself is stopped. |
| */ |
| public void stopDiscover(P2pPeerListener listener) { |
| if (DEBUG) Log.d(TAG, "stopDiscover"); |
| if (mPeerDiscovery != null) { |
| mPeerDiscovery.removeListener(listener); |
| if (mPeerDiscovery.getListeners().isEmpty()) { |
| mPeerDiscovery.cancel(); |
| mPeerDiscovery = null; |
| } |
| } |
| } |
| |
| /** |
| * Request connection to a peer (which may already be connected) at least until stopped. Keeps |
| * the current connection open as long as it might be useful. |
| */ |
| public void connect(WifiP2pDevice peer, P2pConnectionListener listener) { |
| if (DEBUG) Log.d(TAG, "connect(" + toString(peer) + ")"); |
| |
| if (mP2pManager == null) { |
| // Device has no P2P support so indicate failure |
| mService.getMainHandler().post(listener::onConnectionClosed); |
| return; |
| } |
| |
| // Check for competing connection |
| if (mConnection != null && !peer.deviceAddress.equals(mConnection.getPeer() |
| .deviceAddress)) { |
| if (mConnection.getListenerCount() == 1) { |
| // The only listener is our internal one, so close this connection to make room |
| mConnection.close(); |
| mConnection = null; |
| } else { |
| // Cannot open connection |
| mService.getMainHandler().post(listener::onConnectionClosed); |
| return; |
| } |
| } |
| |
| // Check for existing connection to the same device |
| if (mConnection == null) { |
| // Create a new connection request with our internal listener |
| mConnection = new P2pConnectionProcedure(mService, mP2pManager, peer, |
| new P2pConnectionListener() { |
| @Override |
| public void onConnectionOpen(String networkInterface, WifiP2pInfo info) { |
| mConnectedInterface = networkInterface; |
| } |
| |
| @Override |
| public void onConnectionClosed() { |
| mConnectedInterface = null; |
| } |
| |
| @Override |
| public void onConnectionDelayed(boolean delayed) { |
| } |
| }); |
| } |
| mConnection.addListener(listener); |
| } |
| |
| /** |
| * Give up on the connection request associated with a listener. The connection will stay |
| * open as long as other requests exist. |
| */ |
| void stopConnect(P2pConnectionListener listener) { |
| if (mConnection == null || !mConnection.hasListener(listener)) { |
| return; |
| } |
| |
| if (DEBUG) Log.d(TAG, "stopConnect " + toString(mConnection.getPeer())); |
| mConnection.removeListener(listener); |
| |
| // If current connection attempt is incomplete and no longer required, close it. |
| if (mConnection.getListenerCount() == 1 && mConnectedInterface == null) { |
| if (DEBUG) Log.d(TAG, "Abandoning connection request"); |
| mConnection.close(); |
| mConnection = null; |
| } |
| } |
| |
| /** Return the current connection procedure, if any */ |
| P2pConnectionProcedure getConnection() { |
| return mConnection; |
| } |
| |
| /** Return the current connected interface, if any */ |
| public String getConnectedInterface() { |
| return mConnectedInterface; |
| } |
| |
| /** Forcibly stops all connections/discoveries in progress, if any */ |
| public void stopAll() { |
| if (mConnection != null) { |
| mConnection.close(); |
| mConnection = null; |
| mConnectedInterface = null; |
| } |
| if (mPeerDiscovery != null) { |
| mPeerDiscovery.cancel(); |
| mPeerDiscovery = null; |
| } |
| } |
| } |