blob: 1c9ce30e9604c93efc3e380f343aec658cd37fce [file] [log] [blame]
/*
* 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;
}
}
}