• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 android.net.wifi.p2p;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.compat.annotation.UnsupportedAppUsage;
24 import android.net.MacAddress;
25 import android.net.wifi.OuiKeyedData;
26 import android.net.wifi.ParcelUtil;
27 import android.net.wifi.ScanResult;
28 import android.net.wifi.util.Environment;
29 import android.os.Build;
30 import android.os.Parcel;
31 import android.os.Parcelable;
32 import android.util.Log;
33 
34 import androidx.annotation.RequiresApi;
35 
36 import com.android.modules.utils.build.SdkLevel;
37 import com.android.wifi.flags.Flags;
38 
39 import java.net.InetAddress;
40 import java.net.UnknownHostException;
41 import java.util.ArrayList;
42 import java.util.Collections;
43 import java.util.List;
44 import java.util.Objects;
45 import java.util.regex.Matcher;
46 import java.util.regex.Pattern;
47 
48 /**
49  * A class representing a Wi-Fi p2p device
50  *
51  * Note that the operations are not thread safe
52  * {@see WifiP2pManager}
53  */
54 public class WifiP2pDevice implements Parcelable {
55 
56     private static final String TAG = "WifiP2pDevice";
57 
58     /**
59      * The device name is a user friendly string to identify a Wi-Fi p2p device
60      */
61     public String deviceName = "";
62 
63     /**
64      * The device MAC address uniquely identifies a Wi-Fi p2p device
65      */
66     public String deviceAddress = "";
67     /**
68      * The device interface MAC address. This field is valid when the device is a part of the group
69      */
70     @Nullable private MacAddress mInterfaceMacAddress;
71 
72     /**
73      * The IP address of the device. This field is valid when the device is a part of the group.
74      */
75     @Nullable private InetAddress mIpAddress;
76 
77     /**
78      * Primary device type identifies the type of device. For example, an application
79      * could filter the devices discovered to only display printers if the purpose is to
80      * enable a printing action from the user. See the Wi-Fi Direct technical specification
81      * for the full list of standard device types supported.
82      */
83     public String primaryDeviceType;
84 
85     /**
86      * Secondary device type is an optional attribute that can be provided by a device in
87      * addition to the primary device type.
88      */
89     public String secondaryDeviceType;
90 
91 
92     // These definitions match the ones in wpa_supplicant
93     /* WPS config methods supported */
94     private static final int WPS_CONFIG_DISPLAY         = 0x0008;
95     private static final int WPS_CONFIG_PUSHBUTTON      = 0x0080;
96     private static final int WPS_CONFIG_KEYPAD          = 0x0100;
97 
98     /* Device Capability bitmap */
99     private static final int DEVICE_CAPAB_SERVICE_DISCOVERY         = 1;
100     @SuppressWarnings("unused")
101     private static final int DEVICE_CAPAB_CLIENT_DISCOVERABILITY    = 1<<1;
102     @SuppressWarnings("unused")
103     private static final int DEVICE_CAPAB_CONCURRENT_OPER           = 1<<2;
104     @SuppressWarnings("unused")
105     private static final int DEVICE_CAPAB_INFRA_MANAGED             = 1<<3;
106     @SuppressWarnings("unused")
107     private static final int DEVICE_CAPAB_DEVICE_LIMIT              = 1<<4;
108     private static final int DEVICE_CAPAB_INVITATION_PROCEDURE      = 1<<5;
109 
110     /* Group Capability bitmap */
111     private static final int GROUP_CAPAB_GROUP_OWNER                = 1;
112     @SuppressWarnings("unused")
113     private static final int GROUP_CAPAB_PERSISTENT_GROUP           = 1<<1;
114     private static final int GROUP_CAPAB_GROUP_LIMIT                = 1<<2;
115     @SuppressWarnings("unused")
116     private static final int GROUP_CAPAB_INTRA_BSS_DIST             = 1<<3;
117     @SuppressWarnings("unused")
118     private static final int GROUP_CAPAB_CROSS_CONN                 = 1<<4;
119     @SuppressWarnings("unused")
120     private static final int GROUP_CAPAB_PERSISTENT_RECONN          = 1<<5;
121     @SuppressWarnings("unused")
122     private static final int GROUP_CAPAB_GROUP_FORMATION            = 1<<6;
123 
124     /**
125      * WPS config methods supported
126      * @hide
127      */
128     @UnsupportedAppUsage
129     public int wpsConfigMethodsSupported;
130 
131     /**
132      * Device capability
133      * @hide
134      */
135     @UnsupportedAppUsage
136     public int deviceCapability;
137 
138     /**
139      * Group capability
140      * @hide
141      */
142     @UnsupportedAppUsage
143     public int groupCapability;
144 
145     public static final int CONNECTED   = 0;
146     public static final int INVITED     = 1;
147     public static final int FAILED      = 2;
148     public static final int AVAILABLE   = 3;
149     public static final int UNAVAILABLE = 4;
150 
151     /** Device connection status */
152     public int status = UNAVAILABLE;
153 
154     /** @hide */
155     @UnsupportedAppUsage
156     public WifiP2pWfdInfo wfdInfo;
157 
158     /** This stores vendor-specific information element from the native side. */
159     private List<ScanResult.InformationElement> mVendorElements;
160 
161     /** Detailed device string pattern with WFD info
162      * Example:
163      *  P2P-DEVICE-FOUND 00:18:6b:de:a3:6e p2p_dev_addr=00:18:6b:de:a3:6e
164      *  pri_dev_type=1-0050F204-1 name='DWD-300-DEA36E' config_methods=0x188
165      *  dev_capab=0x21 group_capab=0x9
166      */
167     private static final Pattern detailedDevicePattern = Pattern.compile(
168             "((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) "
169             + "(\\d+ )?"
170             + "p2p_dev_addr=((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) "
171             + "pri_dev_type=(\\d+-[0-9a-fA-F]+-\\d+) "
172             + "name='(.*)' "
173             + "config_methods=(0x[0-9a-fA-F]+) "
174             + "dev_capab=(0x[0-9a-fA-F]+) "
175             + "group_capab=(0x[0-9a-fA-F]+)"
176             + "( wfd_dev_info=0x([0-9a-fA-F]{12}))?"
177             + "( wfd_r2_dev_info=0x([0-9a-fA-F]{4}))?"
178     );
179 
180     /** 2 token device address pattern
181      * Example:
182      *  P2P-DEVICE-LOST p2p_dev_addr=fa:7b:7a:42:02:13
183      *  AP-STA-DISCONNECTED 42:fc:89:a8:96:09
184      */
185     private static final Pattern twoTokenPattern = Pattern.compile(
186         "(p2p_dev_addr=)?((?:[0-9a-f]{2}:){5}[0-9a-f]{2})"
187     );
188 
189     /** 3 token device address pattern
190      * Example:
191      *  AP-STA-CONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=fa:7b:7a:42:02:13
192      *  AP-STA-DISCONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=fa:7b:7a:42:02:13
193      */
194     private static final Pattern threeTokenPattern = Pattern.compile(
195         "(?:[0-9a-f]{2}:){5}[0-9a-f]{2} p2p_dev_addr=((?:[0-9a-f]{2}:){5}[0-9a-f]{2})"
196     );
197 
198     /** List of {@link OuiKeyedData} providing vendor-specific configuration data. */
199     private @NonNull List<OuiKeyedData> mVendorData = Collections.emptyList();
200 
201     /**
202      * Return the vendor-provided configuration data, if it exists. See also {@link
203      * #setVendorData(List)}
204      *
205      * @return Vendor configuration data, or empty list if it does not exist.
206      * @hide
207      */
208     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
209     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
210     @SystemApi
211     @NonNull
getVendorData()212     public List<OuiKeyedData> getVendorData() {
213         if (!SdkLevel.isAtLeastV()) {
214             throw new UnsupportedOperationException();
215         }
216         return mVendorData;
217     }
218     /**
219      * The bitmask of supported {@code PAIRING_BOOTSTRAPPING_METHOD_*} methods used to enable
220      * the pairing bootstrapping between bootstrapping initiator and a bootstrapping responder.
221      */
222     private int mPairingBootstrappingMethods;
223 
WifiP2pDevice()224     public WifiP2pDevice() {
225     }
226 
227     /**
228      * @param string formats supported include
229      *  P2P-DEVICE-FOUND fa:7b:7a:42:02:13 p2p_dev_addr=fa:7b:7a:42:02:13
230      *  pri_dev_type=1-0050F204-1 name='p2p-TEST1' config_methods=0x188 dev_capab=0x27
231      *  group_capab=0x0 wfd_dev_info=000006015d022a0032
232      *
233      *  P2P-DEVICE-LOST p2p_dev_addr=fa:7b:7a:42:02:13
234      *
235      *  AP-STA-CONNECTED 42:fc:89:a8:96:09 [p2p_dev_addr=02:90:4c:a0:92:54]
236      *
237      *  AP-STA-DISCONNECTED 42:fc:89:a8:96:09 [p2p_dev_addr=02:90:4c:a0:92:54]
238      *
239      *  fa:7b:7a:42:02:13
240      *
241      *  Note: The events formats can be looked up in the wpa_supplicant code
242      * @hide
243      */
244     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
WifiP2pDevice(String string)245     public WifiP2pDevice(String string) throws IllegalArgumentException {
246         String[] tokens = string.split("[ \n]");
247         Matcher match;
248 
249         if (tokens.length < 1) {
250             throw new IllegalArgumentException("Malformed supplicant event");
251         }
252 
253         switch (tokens.length) {
254             case 1:
255                 /* Just a device address */
256                 deviceAddress = string;
257                 return;
258             case 2:
259                 match = twoTokenPattern.matcher(string);
260                 if (!match.find()) {
261                     throw new IllegalArgumentException("Malformed supplicant event");
262                 }
263                 deviceAddress = match.group(2);
264                 return;
265             case 3:
266                 match = threeTokenPattern.matcher(string);
267                 if (!match.find()) {
268                     throw new IllegalArgumentException("Malformed supplicant event");
269                 }
270                 deviceAddress = match.group(1);
271                 return;
272             default:
273                 match = detailedDevicePattern.matcher(string);
274                 if (!match.find()) {
275                     throw new IllegalArgumentException("Malformed supplicant event");
276                 }
277 
278                 deviceAddress = match.group(3);
279                 primaryDeviceType = match.group(4);
280                 deviceName = match.group(5);
281                 wpsConfigMethodsSupported = parseHex(match.group(6));
282                 deviceCapability = parseHex(match.group(7));
283                 groupCapability = parseHex(match.group(8));
284                 if (match.group(9) != null) {
285                     String str = match.group(10);
286                     if (null == str) break;
287                     wfdInfo = new WifiP2pWfdInfo(parseHex(str.substring(0,4)),
288                             parseHex(str.substring(4,8)),
289                             parseHex(str.substring(8,12)));
290                     if (match.group(11) != null && SdkLevel.isAtLeastS()) {
291                         String r2str = match.group(12);
292                         if (null == r2str) break;
293                         wfdInfo.setR2DeviceType(parseHex(r2str.substring(0, 4)));
294                     }
295                 }
296                 break;
297         }
298 
299         if (tokens[0].startsWith("P2P-DEVICE-FOUND")) {
300             status = AVAILABLE;
301         }
302     }
303 
304     /** The Wifi Display information for this device, or null if unavailable. */
305     @Nullable
getWfdInfo()306     public WifiP2pWfdInfo getWfdInfo() {
307         return wfdInfo;
308     }
309 
310     /** Returns true if WPS push button configuration is supported */
wpsPbcSupported()311     public boolean wpsPbcSupported() {
312         return (wpsConfigMethodsSupported & WPS_CONFIG_PUSHBUTTON) != 0;
313     }
314 
315     /** Returns true if WPS keypad configuration is supported */
wpsKeypadSupported()316     public boolean wpsKeypadSupported() {
317         return (wpsConfigMethodsSupported & WPS_CONFIG_KEYPAD) != 0;
318     }
319 
320     /** Returns true if WPS display configuration is supported */
wpsDisplaySupported()321     public boolean wpsDisplaySupported() {
322         return (wpsConfigMethodsSupported & WPS_CONFIG_DISPLAY) != 0;
323     }
324 
325     /** Returns true if the device is capable of service discovery */
isServiceDiscoveryCapable()326     public boolean isServiceDiscoveryCapable() {
327         return (deviceCapability & DEVICE_CAPAB_SERVICE_DISCOVERY) != 0;
328     }
329 
330     /** Returns true if the device is capable of invitation {@hide}*/
isInvitationCapable()331     public boolean isInvitationCapable() {
332         return (deviceCapability & DEVICE_CAPAB_INVITATION_PROCEDURE) != 0;
333     }
334 
335     /** Returns true if the device reaches the limit. {@hide}*/
isDeviceLimit()336     public boolean isDeviceLimit() {
337         return (deviceCapability & DEVICE_CAPAB_DEVICE_LIMIT) != 0;
338     }
339 
340     /** Returns true if the device is a group owner */
isGroupOwner()341     public boolean isGroupOwner() {
342         return (groupCapability & GROUP_CAPAB_GROUP_OWNER) != 0;
343     }
344 
345     /** Returns true if the group reaches the limit. {@hide}*/
isGroupLimit()346     public boolean isGroupLimit() {
347         return (groupCapability & GROUP_CAPAB_GROUP_LIMIT) != 0;
348     }
349 
350     /**
351      * Update this device's details using another {@link WifiP2pDevice} instance.
352      * This will throw an exception if the device address does not match.
353      *
354      * @param device another instance of {@link WifiP2pDevice} used to update this instance.
355      * @throws IllegalArgumentException if the device is null or the device address does not match
356      */
update(@onNull WifiP2pDevice device)357     public void update(@NonNull WifiP2pDevice device) {
358         updateSupplicantDetails(device);
359         status = device.status;
360     }
361 
362     /** Updates details obtained from supplicant @hide */
updateSupplicantDetails(WifiP2pDevice device)363     public void updateSupplicantDetails(WifiP2pDevice device) {
364         if (device == null) {
365             throw new IllegalArgumentException("device is null");
366         }
367         if (device.deviceAddress == null) {
368             throw new IllegalArgumentException("deviceAddress is null");
369         }
370         if (!deviceAddress.equals(device.deviceAddress)) {
371             throw new IllegalArgumentException("deviceAddress does not match");
372         }
373         mInterfaceMacAddress = device.mInterfaceMacAddress;
374         deviceName = device.deviceName;
375         primaryDeviceType = device.primaryDeviceType;
376         secondaryDeviceType = device.secondaryDeviceType;
377         wpsConfigMethodsSupported = device.wpsConfigMethodsSupported;
378         deviceCapability = device.deviceCapability;
379         groupCapability = device.groupCapability;
380         wfdInfo = device.wfdInfo;
381     }
382 
383     /**
384      * Set vendor-specific information elements.
385      * @hide
386      */
setVendorElements( List<ScanResult.InformationElement> vendorElements)387     public void setVendorElements(
388             List<ScanResult.InformationElement> vendorElements) {
389         if (vendorElements == null) {
390             mVendorElements = null;
391             return;
392         }
393         mVendorElements = new ArrayList<>(vendorElements);
394     }
395 
396     /**
397      * Set additional vendor-provided configuration data.
398      *
399      * @param vendorData List of {@link android.net.wifi.OuiKeyedData} containing the
400      *                   vendor-provided configuration data. Note that multiple elements with
401      *                   the same OUI are allowed.
402      * @hide
403      */
404     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
405     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
406     @SystemApi
setVendorData(@onNull List<OuiKeyedData> vendorData)407     public void setVendorData(@NonNull List<OuiKeyedData> vendorData) {
408         if (!SdkLevel.isAtLeastV()) {
409             throw new UnsupportedOperationException();
410         }
411         if (vendorData == null) {
412             throw new IllegalArgumentException("setVendorData received a null value");
413         }
414         mVendorData = vendorData;
415     }
416 
417     /**
418      * Get the vendor-specific information elements received as part of the discovery
419      * of the peer device.
420      *
421      * @return the list of vendor-specific information elements
422      *         The information element format is defined in the IEEE 802.11-2016 spec
423      *         Table 9-77.
424      */
getVendorElements()425     @NonNull public List<ScanResult.InformationElement> getVendorElements() {
426         if (mVendorElements == null) return Collections.emptyList();
427         return new ArrayList<>(mVendorElements);
428     }
429 
430     /**
431      * Get the device interface MAC address if the device is a part of the group; otherwise null.
432      *
433      * @return the interface MAC address if the device is a part of the group; otherwise null.
434      * @hide
435      */
getInterfaceMacAddress()436     @Nullable public MacAddress getInterfaceMacAddress() {
437         return mInterfaceMacAddress;
438     }
439 
440     /**
441      * Set the device interface MAC address.
442      * @hide
443      */
setInterfaceMacAddress(@ullable MacAddress interfaceAddress)444     public void setInterfaceMacAddress(@Nullable MacAddress interfaceAddress) {
445         mInterfaceMacAddress = interfaceAddress;
446     }
447 
448     /**
449      * Get the IP address of the connected client device.
450      * The application should listen to {@link WifiP2pManager#WIFI_P2P_CONNECTION_CHANGED_ACTION}
451      * broadcast to obtain the IP address of the connected client. When system assigns the IP
452      * address, the connected P2P device information ({@link WifiP2pGroup#getClientList()}) in the
453      * group is updated with the IP address and broadcast the group information using
454      * {@link WifiP2pManager#EXTRA_WIFI_P2P_GROUP} extra of the
455      * {@link WifiP2pManager#WIFI_P2P_CONNECTION_CHANGED_ACTION} broadcast intent.
456      *
457      * Alternatively, the application can request for the group details with
458      * {@link WifiP2pManager#requestGroupInfo} and use ({@link WifiP2pGroup#getClientList()}) to
459      * obtain the connected client details.
460      *
461      * @return the IP address if the device is a part of the group; otherwise null.
462      */
463     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
getIpAddress()464     @Nullable public InetAddress getIpAddress() {
465         return mIpAddress;
466     }
467 
468     /**
469      * Set the IP address of the device.
470      * @hide
471      */
setIpAddress(InetAddress ipAddress)472     public void setIpAddress(InetAddress ipAddress) {
473         mIpAddress = ipAddress;
474     }
475 
476     /**
477      * Returns true if opportunistic bootstrapping method is supported.
478      * Defined in Wi-Fi Alliance Wi-Fi Direct R2 Specification Table 10 - Bootstrapping Methods.
479      */
480     @RequiresApi(Build.VERSION_CODES.BAKLAVA)
481     @FlaggedApi(Flags.FLAG_WIFI_DIRECT_R2)
isOpportunisticBootstrappingMethodSupported()482     public boolean isOpportunisticBootstrappingMethodSupported() {
483         if (!Environment.isSdkAtLeastB()) {
484             throw new UnsupportedOperationException();
485         }
486         return (mPairingBootstrappingMethods & WifiP2pPairingBootstrappingConfig
487                 .PAIRING_BOOTSTRAPPING_METHOD_OPPORTUNISTIC) != 0;
488     }
489 
490     /**
491      * Returns true if pin-code display bootstrapping method is supported.
492      * Defined in Wi-Fi Alliance Wi-Fi Direct R2 Specification Table 10 - Bootstrapping Methods.
493      */
494     @RequiresApi(Build.VERSION_CODES.BAKLAVA)
495     @FlaggedApi(Flags.FLAG_WIFI_DIRECT_R2)
isPinCodeDisplayBootstrappingMethodSupported()496     public boolean isPinCodeDisplayBootstrappingMethodSupported() {
497         if (!Environment.isSdkAtLeastB()) {
498             throw new UnsupportedOperationException();
499         }
500         return (mPairingBootstrappingMethods & WifiP2pPairingBootstrappingConfig
501                 .PAIRING_BOOTSTRAPPING_METHOD_DISPLAY_PINCODE) != 0;
502     }
503 
504     /**
505      * Returns true if passphrase display bootstrapping method is supported.
506      * Defined in Wi-Fi Alliance Wi-Fi Direct R2 Specification Table 10 - Bootstrapping Methods.
507      */
508     @RequiresApi(Build.VERSION_CODES.BAKLAVA)
509     @FlaggedApi(Flags.FLAG_WIFI_DIRECT_R2)
isPassphraseDisplayBootstrappingMethodSupported()510     public boolean isPassphraseDisplayBootstrappingMethodSupported() {
511         if (!Environment.isSdkAtLeastB()) {
512             throw new UnsupportedOperationException();
513         }
514         return (mPairingBootstrappingMethods & WifiP2pPairingBootstrappingConfig
515                 .PAIRING_BOOTSTRAPPING_METHOD_DISPLAY_PASSPHRASE) != 0;
516     }
517 
518     /**
519      * Returns true if pin-code keypad bootstrapping method is supported.
520      * Defined in Wi-Fi Alliance Wi-Fi Direct R2 Specification Table 10 - Bootstrapping Methods.
521      */
522     @RequiresApi(Build.VERSION_CODES.BAKLAVA)
523     @FlaggedApi(Flags.FLAG_WIFI_DIRECT_R2)
isPinCodeKeypadBootstrappingMethodSupported()524     public boolean isPinCodeKeypadBootstrappingMethodSupported() {
525         if (!Environment.isSdkAtLeastB()) {
526             throw new UnsupportedOperationException();
527         }
528         return (mPairingBootstrappingMethods & WifiP2pPairingBootstrappingConfig
529                 .PAIRING_BOOTSTRAPPING_METHOD_KEYPAD_PINCODE) != 0;
530     }
531 
532     /**
533      * Returns true if passphrase keypad bootstrapping method is supported.
534      * Defined in Wi-Fi Alliance Wi-Fi Direct R2 Specification Table 10 - Bootstrapping Methods.
535      */
536     @RequiresApi(Build.VERSION_CODES.BAKLAVA)
537     @FlaggedApi(Flags.FLAG_WIFI_DIRECT_R2)
isPassphraseKeypadBootstrappingMethodSupported()538     public boolean isPassphraseKeypadBootstrappingMethodSupported() {
539         if (!Environment.isSdkAtLeastB()) {
540             throw new UnsupportedOperationException();
541         }
542         return (mPairingBootstrappingMethods & WifiP2pPairingBootstrappingConfig
543                 .PAIRING_BOOTSTRAPPING_METHOD_KEYPAD_PASSPHRASE) != 0;
544     }
545 
546     /**
547      * Get the supported pairing bootstrapping methods for framework internal usage.
548      * @hide
549      */
getPairingBootStrappingMethods()550     public int getPairingBootStrappingMethods() {
551         if (!Environment.isSdkAtLeastB()) {
552             throw new UnsupportedOperationException();
553         }
554         return mPairingBootstrappingMethods;
555     }
556 
557     /**
558      * Set the supported pairing bootstrapping methods.
559      *
560      * @param methods Bitmask of supported
561      * {@code WifiP2pPairingBootstrappingConfig.PAIRING_BOOTSTRAPPING_METHOD_*}
562      * @hide
563      */
setPairingBootStrappingMethods( @ifiP2pPairingBootstrappingConfig.PairingBootstrappingMethod int methods)564     public void setPairingBootStrappingMethods(
565             @WifiP2pPairingBootstrappingConfig.PairingBootstrappingMethod int methods) {
566         if (!Environment.isSdkAtLeastB()) {
567             throw new UnsupportedOperationException();
568         }
569         mPairingBootstrappingMethods = methods;
570     }
571 
572     /**
573      * Store the Device Identity Resolution (DIR) Info received in USD frame for framework
574      * internal usage.
575      * @hide
576      */
577     @Nullable
578     public WifiP2pDirInfo dirInfo;
579 
580     @Override
equals(Object obj)581     public boolean equals(Object obj) {
582         if (this == obj) return true;
583         if (!(obj instanceof WifiP2pDevice)) return false;
584 
585         WifiP2pDevice other = (WifiP2pDevice) obj;
586         if (other == null || other.deviceAddress == null) {
587             return (deviceAddress == null);
588         }
589         return other.deviceAddress.equals(deviceAddress);
590     }
591 
592     @Override
hashCode()593     public int hashCode() {
594         return Objects.hashCode(deviceAddress);
595     }
596 
597     @Override
toString()598     public String toString() {
599         StringBuffer sbuf = new StringBuffer();
600         sbuf.append("Device: ").append(deviceName);
601         sbuf.append("\n deviceAddress: ").append(deviceAddress);
602         sbuf.append("\n interfaceMacAddress: ")
603                 .append(mInterfaceMacAddress == null ? "none" : mInterfaceMacAddress.toString());
604         sbuf.append("\n ipAddress: ")
605                 .append(mIpAddress == null ? "none" : mIpAddress.getHostAddress());
606         sbuf.append("\n primary type: ").append(primaryDeviceType);
607         sbuf.append("\n secondary type: ").append(secondaryDeviceType);
608         sbuf.append("\n wps: ").append(wpsConfigMethodsSupported);
609         sbuf.append("\n grpcapab: ").append(groupCapability);
610         sbuf.append("\n devcapab: ").append(deviceCapability);
611         sbuf.append("\n status: ").append(status);
612         sbuf.append("\n wfdInfo: ").append(wfdInfo);
613         sbuf.append("\n vendorElements: ").append(mVendorElements);
614         sbuf.append("\n vendorData: ").append(mVendorData);
615         sbuf.append("\n Pairing Bootstrapping Methods: ").append(mPairingBootstrappingMethods);
616         return sbuf.toString();
617     }
618 
619     /** Implement the Parcelable interface */
620     @Override
describeContents()621     public int describeContents() {
622         return 0;
623     }
624 
625     /** copy constructor */
WifiP2pDevice(WifiP2pDevice source)626     public WifiP2pDevice(WifiP2pDevice source) {
627         if (source != null) {
628             deviceName = source.deviceName;
629             deviceAddress = source.deviceAddress;
630             mInterfaceMacAddress = source.mInterfaceMacAddress;
631             mIpAddress = source.mIpAddress;
632             primaryDeviceType = source.primaryDeviceType;
633             secondaryDeviceType = source.secondaryDeviceType;
634             wpsConfigMethodsSupported = source.wpsConfigMethodsSupported;
635             deviceCapability = source.deviceCapability;
636             groupCapability = source.groupCapability;
637             status = source.status;
638             if (source.wfdInfo != null) {
639                 wfdInfo = new WifiP2pWfdInfo(source.wfdInfo);
640             }
641             if (null != source.mVendorElements) {
642                 mVendorElements = new ArrayList<>(source.mVendorElements);
643             }
644             mVendorData = new ArrayList<>(source.mVendorData);
645             mPairingBootstrappingMethods = source.mPairingBootstrappingMethods;
646         }
647     }
648 
649     /** Implement the Parcelable interface */
650     @Override
writeToParcel(Parcel dest, int flags)651     public void writeToParcel(Parcel dest, int flags) {
652         dest.writeString(deviceName);
653         dest.writeString(deviceAddress);
654         dest.writeParcelable(mInterfaceMacAddress, flags);
655         if (mIpAddress != null) {
656             dest.writeByte((byte) 1);
657             dest.writeByteArray(mIpAddress.getAddress());
658         } else {
659             dest.writeByte((byte) 0);
660         }
661         dest.writeString(primaryDeviceType);
662         dest.writeString(secondaryDeviceType);
663         dest.writeInt(wpsConfigMethodsSupported);
664         dest.writeInt(deviceCapability);
665         dest.writeInt(groupCapability);
666         dest.writeInt(status);
667         if (wfdInfo != null) {
668             dest.writeInt(1);
669             wfdInfo.writeToParcel(dest, flags);
670         } else {
671             dest.writeInt(0);
672         }
673         dest.writeTypedList(mVendorElements);
674         dest.writeList(mVendorData);
675         dest.writeInt(mPairingBootstrappingMethods);
676     }
677 
678     /** Implement the Parcelable interface */
679     public static final @android.annotation.NonNull Creator<WifiP2pDevice> CREATOR =
680         new Creator<WifiP2pDevice>() {
681             @Override
682             public WifiP2pDevice createFromParcel(Parcel in) {
683                     WifiP2pDevice device = new WifiP2pDevice();
684                     device.deviceName = in.readString();
685                     device.deviceAddress = in.readString();
686                     device.mInterfaceMacAddress =
687                         in.readParcelable(MacAddress.class.getClassLoader());
688                     if (in.readByte() == 1) {
689                         try {
690                             device.mIpAddress = InetAddress.getByAddress(in.createByteArray());
691                         } catch (UnknownHostException e) {
692                             e.printStackTrace();
693                             return new WifiP2pDevice();
694                         }
695                     }
696                     device.primaryDeviceType = in.readString();
697                     device.secondaryDeviceType = in.readString();
698                     device.wpsConfigMethodsSupported = in.readInt();
699                     device.deviceCapability = in.readInt();
700                     device.groupCapability = in.readInt();
701                     device.status = in.readInt();
702                     if (in.readInt() == 1) {
703                         device.wfdInfo = WifiP2pWfdInfo.CREATOR.createFromParcel(in);
704                     }
705                     device.mVendorElements = in.createTypedArrayList(
706                             ScanResult.InformationElement.CREATOR);
707                     device.mVendorData = ParcelUtil.readOuiKeyedDataList(in);
708                     device.mPairingBootstrappingMethods = in.readInt();
709                     return device;
710             }
711 
712             @Override
713             public WifiP2pDevice[] newArray(int size) {
714                 return new WifiP2pDevice[size];
715             }
716         };
717 
718     //supported formats: 0x1abc, 0X1abc, 1abc
parseHex(String hexString)719     private int parseHex(String hexString) {
720         int num = 0;
721         if (hexString.startsWith("0x") || hexString.startsWith("0X")) {
722             hexString = hexString.substring(2);
723         }
724 
725         try {
726             num = Integer.parseInt(hexString, 16);
727         } catch(NumberFormatException e) {
728             Log.e(TAG, "Failed to parse hex string " + hexString);
729         }
730         return num;
731     }
732 }
733