/* * Copyright (C) 2012 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 android.net.wifi.p2p.nsd; import android.net.wifi.p2p.WifiP2pManager; import android.os.Parcel; import android.os.Parcelable; import java.util.Locale; /** * A class for creating a service discovery request for use with * {@link WifiP2pManager#addServiceRequest} and {@link WifiP2pManager#removeServiceRequest} * *

This class is used to create service discovery request for custom * vendor specific service discovery protocol {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC} * or to search all service protocols {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL}. * *

For the purpose of creating a UPnP or Bonjour service request, use * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest} respectively. * * {@see WifiP2pManager} * {@see WifiP2pUpnpServiceRequest} * {@see WifiP2pDnsSdServiceRequest} */ public class WifiP2pServiceRequest implements Parcelable { /** * Service discovery protocol. It's defined in table63 in Wi-Fi Direct specification. */ private int mProtocolType; /** * The length of the service request TLV. * The value is equal to 2 plus the number of octets in the * query data field. */ private int mLength; /** * Service transaction ID. * This is a nonzero value used to match the service request/response TLVs. */ private int mTransId; /** * The hex dump string of query data for the requested service information. * * e.g) DnsSd apple file sharing over tcp (dns name=_afpovertcp._tcp.local.) * 0b5f6166706f766572746370c00c000c01 */ private String mQuery; /** * This constructor is only used in newInstance(). * * @param protocolType service discovery protocol. * @param query The part of service specific query. * @hide */ protected WifiP2pServiceRequest(int protocolType, String query) { validateQuery(query); mProtocolType = protocolType; mQuery = query; if (query != null) { mLength = query.length()/2 + 2; } else { mLength = 2; } } /** * This constructor is only used in Parcelable. * * @param serviceType service discovery type. * @param length the length of service discovery packet. * @param transId the transaction id * @param query The part of service specific query. */ private WifiP2pServiceRequest(int serviceType, int length, int transId, String query) { mProtocolType = serviceType; mLength = length; mTransId = transId; mQuery = query; } /** * Return transaction id. * * @return transaction id * @hide */ public int getTransactionId() { return mTransId; } /** * Set transaction id. * * @param id * @hide */ public void setTransactionId(int id) { mTransId = id; } /** * Return wpa_supplicant request string. * * The format is the hex dump of the following frame. *

     * _______________________________________________________________
     * |        Length (2)        |   Type (1)   | Transaction ID (1) |
     * |                  Query Data (variable)                       |
     * 
* * @return wpa_supplicant request string. * @hide */ public String getSupplicantQuery() { StringBuffer sb = new StringBuffer(); // length is retained as little endian format. sb.append(String.format(Locale.US, "%02x", (mLength) & 0xff)); sb.append(String.format(Locale.US, "%02x", (mLength >> 8) & 0xff)); sb.append(String.format(Locale.US, "%02x", mProtocolType)); sb.append(String.format(Locale.US, "%02x", mTransId)); if (mQuery != null) { sb.append(mQuery); } return sb.toString(); } /** * Validate query. * *

If invalid, throw IllegalArgumentException. * @param query The part of service specific query. */ private void validateQuery(String query) { if (query == null) { return; } int UNSIGNED_SHORT_MAX = 0xffff; if (query.length()%2 == 1) { throw new IllegalArgumentException( "query size is invalid. query=" + query); } if (query.length()/2 > UNSIGNED_SHORT_MAX) { throw new IllegalArgumentException( "query size is too large. len=" + query.length()); } // check whether query is hex string. query = query.toLowerCase(Locale.ROOT); char[] chars = query.toCharArray(); for (char c: chars) { if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))){ throw new IllegalArgumentException( "query should be hex string. query=" + query); } } } /** * Create a service discovery request. * * @param protocolType can be {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL} * or {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}. * In order to create a UPnP or Bonjour service request, use * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest} * respectively * * @param queryData hex string that is vendor specific. Can be null. * @return service discovery request. */ public static WifiP2pServiceRequest newInstance(int protocolType, String queryData) { return new WifiP2pServiceRequest(protocolType, queryData); } /** * Create a service discovery request. * * @param protocolType can be {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL} * or {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}. * In order to create a UPnP or Bonjour service request, use * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest} * respectively * * @return service discovery request. */ public static WifiP2pServiceRequest newInstance(int protocolType ) { return new WifiP2pServiceRequest(protocolType, null); } @Override public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof WifiP2pServiceRequest)) { return false; } WifiP2pServiceRequest req = (WifiP2pServiceRequest)o; /* * Not compare transaction id. * Transaction id may be changed on each service discovery operation. */ if ((req.mProtocolType != mProtocolType) || (req.mLength != mLength)) { return false; } if (req.mQuery == null && mQuery == null) { return true; } else if (req.mQuery != null) { return req.mQuery.equals(mQuery); } return false; } @Override public int hashCode() { int result = 17; result = 31 * result + mProtocolType; result = 31 * result + mLength; result = 31 * result + (mQuery == null ? 0 : mQuery.hashCode()); return result; } /** Implement the Parcelable interface {@hide} */ public int describeContents() { return 0; } /** Implement the Parcelable interface {@hide} */ public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mProtocolType); dest.writeInt(mLength); dest.writeInt(mTransId); dest.writeString(mQuery); } /** Implement the Parcelable interface {@hide} */ public static final Creator CREATOR = new Creator() { public WifiP2pServiceRequest createFromParcel(Parcel in) { int servType = in.readInt(); int length = in.readInt(); int transId = in.readInt(); String query = in.readString(); return new WifiP2pServiceRequest(servType, length, transId, query); } public WifiP2pServiceRequest[] newArray(int size) { return new WifiP2pServiceRequest[size]; } }; }