• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.android.bips.discovery.P2pDiscovery.toPrinter;
20 
21 import android.net.wifi.p2p.WifiP2pDevice;
22 import android.net.wifi.p2p.WifiP2pInfo;
23 import android.util.Log;
24 
25 import com.android.bips.BuiltInPrintService;
26 import com.android.bips.DelayedAction;
27 import com.android.bips.discovery.ConnectionListener;
28 import com.android.bips.discovery.DiscoveredPrinter;
29 import com.android.bips.discovery.Discovery;
30 import com.android.bips.discovery.P2pDiscovery;
31 import com.android.bips.jni.LocalPrinterCapabilities;
32 
33 import java.net.Inet4Address;
34 import java.net.NetworkInterface;
35 import java.net.SocketException;
36 import java.net.UnknownHostException;
37 import java.util.Arrays;
38 
39 /**
40  * Manage the process of connecting to a P2P device, discovering a printer on the new network, and
41  * verifying its capabilities.
42  */
43 public class P2pPrinterConnection implements Discovery.Listener, P2pConnectionListener,
44         P2pPeerListener {
45     private static final String TAG = P2pPrinterConnection.class.getSimpleName();
46     private static final boolean DEBUG = false;
47     private static final int TIMEOUT_DISCOVERY = 15 * 1000;
48 
49     private final BuiltInPrintService mService;
50     private final Discovery mMdnsDiscovery;
51     private ConnectionListener mListener;
52 
53     private DiscoveredPrinter mPrinter;
54     private WifiP2pDevice mPeer;
55     private NetworkInterface mInterface;
56     private DelayedAction mMdnsDiscoveryTimeout;
57 
P2pPrinterConnection(BuiltInPrintService service, ConnectionListener listener)58     private P2pPrinterConnection(BuiltInPrintService service, ConnectionListener listener) {
59         mService = service;
60         mListener = listener;
61         mMdnsDiscovery = mService.getMdnsDiscovery();
62     }
63 
64     /** Create a new connection to a known P2P peer device */
P2pPrinterConnection(BuiltInPrintService service, WifiP2pDevice peer, ConnectionListener listener)65     public P2pPrinterConnection(BuiltInPrintService service, WifiP2pDevice peer,
66             ConnectionListener listener) {
67         this(service, listener);
68         if (DEBUG) Log.d(TAG, "Connecting to " + P2pMonitor.toString(peer));
69         // Initialize mPrinter to handle onPeerFound callback for re-discover cases
70         mPrinter = toPrinter(peer);
71         connectToPeer(peer);
72     }
73 
74     /** Re-discover and create a new connection to a previously discovered P2P device */
P2pPrinterConnection(BuiltInPrintService service, DiscoveredPrinter printer, ConnectionListener listener)75     public P2pPrinterConnection(BuiltInPrintService service, DiscoveredPrinter printer,
76             ConnectionListener listener) {
77         this(service, listener);
78         if (DEBUG) Log.d(TAG, "Connecting to " + printer);
79         if (P2pUtils.isOnConnectedInterface(service, printer)) {
80             WifiP2pDevice peer = service.getP2pMonitor().getConnection().getPeer();
81             connectToPeer(peer);
82             return;
83         }
84 
85         mPrinter = printer;
86         service.getP2pMonitor().discover(this);
87     }
88 
connectToPeer(WifiP2pDevice peer)89     private void connectToPeer(WifiP2pDevice peer) {
90         mPeer = peer;
91         mService.getP2pMonitor().connect(mPeer, this, this);
92     }
93 
94     @Override
onPeerFound(WifiP2pDevice peer)95     public void onPeerFound(WifiP2pDevice peer) {
96         if (mListener == null) {
97             return;
98         }
99 
100         String address = mPrinter.path.getHost().replaceAll("-", ":");
101 
102         if (peer.deviceAddress.equals(address)) {
103             mService.getP2pMonitor().stopDiscover(this);
104             // Stop discovery and start validation
105             connectToPeer(peer);
106         }
107     }
108 
109     @Override
onPeerLost(WifiP2pDevice peer)110     public void onPeerLost(WifiP2pDevice peer) {
111         // Ignored
112     }
113 
114     @Override
onConnectionOpen(String networkInterface, WifiP2pInfo info)115     public void onConnectionOpen(String networkInterface, WifiP2pInfo info) {
116         if (mListener == null) {
117             return;
118         }
119 
120         try {
121             mInterface = NetworkInterface.getByName(networkInterface);
122         } catch (SocketException ignored) {
123         }
124 
125         if (mInterface == null) {
126             if (DEBUG) Log.d(TAG, "Failed to get interface from " + networkInterface);
127             mListener.onConnectionComplete(null);
128             close();
129             return;
130         }
131 
132         if (DEBUG) Log.d(TAG, "Connected on network interface " + mInterface);
133 
134         // Timeout after a while if MDNS does not find a printer
135         mMdnsDiscoveryTimeout = mService.delay(TIMEOUT_DISCOVERY, () -> {
136             mMdnsDiscovery.stop(this);
137             if (mListener != null) {
138                 mListener.onConnectionComplete(null);
139             }
140             close();
141         });
142 
143         mMdnsDiscovery.start(this);
144     }
145 
146     @Override
onConnectionClosed()147     public void onConnectionClosed() {
148         if (DEBUG) Log.d(TAG, "closed/failed connection to " + P2pMonitor.toString(mPeer));
149         if (mListener != null) {
150             mListener.onConnectionComplete(null);
151         }
152         close();
153     }
154 
155     @Override
onConnectionDelayed(boolean delayed)156     public void onConnectionDelayed(boolean delayed) {
157         if (mListener == null) {
158             return;
159         }
160         mListener.onConnectionDelayed(delayed);
161     }
162 
163     @Override
onPrinterFound(DiscoveredPrinter printer)164     public void onPrinterFound(DiscoveredPrinter printer) {
165         if (DEBUG) Log.d(TAG, "onPrinterFound(" + printer + ")");
166         if (mListener == null) {
167             return;
168         }
169 
170         Inet4Address printerAddress;
171         try {
172             printerAddress = (Inet4Address) Inet4Address.getByName(printer.path.getHost());
173         } catch (UnknownHostException e) {
174             return;
175         }
176 
177         if (mInterface != null && P2pUtils.isOnInterface(mInterface, printerAddress)) {
178             // Stop discovery and start capabilities query
179             mMdnsDiscovery.stop(this);
180             mMdnsDiscoveryTimeout.cancel();
181             mService.getCapabilitiesCache().request(printer, true, capabilities ->
182                     onCapabilities(printer, capabilities));
183         }
184     }
185 
onCapabilities(DiscoveredPrinter printer, LocalPrinterCapabilities capabilities)186     private void onCapabilities(DiscoveredPrinter printer, LocalPrinterCapabilities capabilities) {
187         if (mListener == null) {
188             return;
189         }
190 
191         if (DEBUG) Log.d(TAG, "Printer " + printer + " caps=" + capabilities);
192         if (capabilities == null) {
193             mListener.onConnectionComplete(null);
194             close();
195         } else {
196             // Make a copy of the printer bearing its P2P path as primary and discovered path
197             // as secondary
198             DiscoveredPrinter p2pPrinter = new DiscoveredPrinter(printer.uuid, printer.name,
199                     Arrays.asList(P2pDiscovery.toPath(mPeer), printer.path), printer.location);
200             mListener.onConnectionComplete(p2pPrinter);
201         }
202     }
203 
204     @Override
onPrinterLost(DiscoveredPrinter printer)205     public void onPrinterLost(DiscoveredPrinter printer) {
206     }
207 
208     /** Close the connection and any intermediate procedures */
close()209     public void close() {
210         if (DEBUG) Log.d(TAG, "close()");
211         mMdnsDiscovery.stop(this);
212         if (mMdnsDiscoveryTimeout != null) {
213             mMdnsDiscoveryTimeout.cancel();
214         }
215         mService.getP2pMonitor().stopDiscover(this);
216         mService.getP2pMonitor().stopConnect(this);
217 
218         // No further notifications
219         mListener = null;
220     }
221 }
222