17d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff/* 27d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Copyright (C) 2012 The Android Open Source Project 37d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * 47d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Licensed under the Apache License, Version 2.0 (the "License"); 57d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * you may not use this file except in compliance with the License. 67d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * You may obtain a copy of the License at 77d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * 87d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * http://www.apache.org/licenses/LICENSE-2.0 97d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * 107d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Unless required by applicable law or agreed to in writing, software 117d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * distributed under the License is distributed on an "AS IS" BASIS, 127d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * See the License for the specific language governing permissions and 147d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * limitations under the License. 157d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */ 167d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 177d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffpackage android.net.nsd; 187d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 193ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriffimport android.annotation.SdkConstant; 203ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriffimport android.annotation.SdkConstant.SdkConstantType; 217d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.content.Context; 227d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Binder; 237d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.IBinder; 247d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Handler; 2522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriffimport android.os.HandlerThread; 267d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Looper; 277d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Message; 287d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.RemoteException; 297d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Messenger; 3092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriffimport android.text.TextUtils; 317d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.util.Log; 3222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriffimport android.util.SparseArray; 3322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 3422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriffimport java.util.concurrent.CountDownLatch; 357d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 367d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport com.android.internal.util.AsyncChannel; 377d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport com.android.internal.util.Protocol; 387d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 397d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff/** 4092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * The Network Service Discovery Manager class provides the API to discover services 4192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * on a network. As an example, if device A and device B are connected over a Wi-Fi 4292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * network, a game registered on device A can be discovered by a game on device 4392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * B. Another example use case is an application discovering printers on the network. 4492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 4592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> The API currently supports DNS based service discovery and discovery is currently 4622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * limited to a local network over Multicast DNS. DNS service discovery is described at 4722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt 487d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * 497d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * <p> The API is asynchronous and responses to requests from an application are on listener 5022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * callbacks on a seperate thread. 5192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 5292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> There are three main operations the API supports - registration, discovery and resolution. 5392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <pre> 5492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * Application start 5592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * | 5622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 5722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | onServiceRegistered() 5822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Register any local services / 5922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * to be advertised with \ 6022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * registerService() onRegistrationFailed() 6122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 6222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 6322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * discoverServices() 6422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 6522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Maintain a list to track 6622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * discovered services 6722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 6822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * |---------> 6922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | | 7022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | onServiceFound() 7122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | | 7222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | add service to list 7322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | | 7422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * |<---------- 7522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 7622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * |---------> 7722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | | 7822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | onServiceLost() 7922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | | 8022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | remove service from list 8122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | | 8222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * |<---------- 8322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 8422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 8522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | Connect to a service 8622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | from list ? 8722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 8822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * resolveService() 8922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 9022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * onServiceResolved() 9122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 9222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Establish connection to service 9322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * with the host and port information 9492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 9592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * </pre> 9692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * An application that needs to advertise itself over a network for other applications to 9792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * discover it can do so with a call to {@link #registerService}. If Example is a http based 9892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * application that can provide HTML data to peer services, it can register a name "Example" 9992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * with service type "_http._tcp". A successful registration is notified with a callback to 10022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link RegistrationListener#onServiceRegistered} and a failure to register is notified 10122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * over {@link RegistrationListener#onRegistrationFailed} 10292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 10392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> A peer application looking for http services can initiate a discovery for "_http._tcp" 10492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * with a call to {@link #discoverServices}. A service found is notified with a callback 10522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * to {@link DiscoveryListener#onServiceFound} and a service lost is notified on 10622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link DiscoveryListener#onServiceLost}. 10792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 10892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> Once the peer application discovers the "Example" http srevice, and needs to receive data 10992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * from the "Example" application, it can initiate a resolve with {@link #resolveService} to 11092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * resolve the host and port details for the purpose of establishing a connection. A successful 11122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * resolve is notified on {@link ResolveListener#onServiceResolved} and a failure is notified 11222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * on {@link ResolveListener#onResolveFailed}. 1137d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * 11492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * Applications can reserve for a service type at 11592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * http://www.iana.org/form/ports-service. Existing services can be found at 11692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml 1177d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * 1187d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Get an instance of this class by calling {@link android.content.Context#getSystemService(String) 1197d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Context.getSystemService(Context.NSD_SERVICE)}. 1207d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * 12122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@see NsdServiceInfo} 1227d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */ 12322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriffpublic final class NsdManager { 1247d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff private static final String TAG = "NsdManager"; 1257d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff INsdManager mService; 1267d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 1273ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff /** 1283ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * Broadcast intent action to indicate whether network service discovery is 1293ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * enabled or disabled. An extra {@link #EXTRA_NSD_STATE} provides the state 1303ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * information as int. 1313ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * 1323ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * @see #EXTRA_NSD_STATE 1333ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff */ 1343ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1356c07ba8183edc593527335238a2c6083392df7bcIrfan Sheriff public static final String ACTION_NSD_STATE_CHANGED = 1363ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff "android.net.nsd.STATE_CHANGED"; 1373ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff 1383ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff /** 1393ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * The lookup key for an int that indicates whether network service discovery is enabled 1403ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * or disabled. Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}. 1413ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * 1423ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * @see #NSD_STATE_DISABLED 1433ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * @see #NSD_STATE_ENABLED 1443ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff */ 1453ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff public static final String EXTRA_NSD_STATE = "nsd_state"; 1463ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff 1473ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff /** 1483ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * Network service discovery is disabled 1493ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * 15054ac7a510245e5f00c16ff5595b6ae8d002c1c3bIrfan Sheriff * @see #ACTION_NSD_STATE_CHANGED 1513ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff */ 1523ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff public static final int NSD_STATE_DISABLED = 1; 1533ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff 1543ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff /** 1553ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * Network service discovery is enabled 1563ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * 15754ac7a510245e5f00c16ff5595b6ae8d002c1c3bIrfan Sheriff * @see #ACTION_NSD_STATE_CHANGED 1583ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff */ 1593ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff public static final int NSD_STATE_ENABLED = 2; 1603ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff 1617d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff private static final int BASE = Protocol.BASE_NSD_MANAGER; 1627d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 1637d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1647d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int DISCOVER_SERVICES = BASE + 1; 1657d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1667d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int DISCOVER_SERVICES_STARTED = BASE + 2; 1677d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1687d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int DISCOVER_SERVICES_FAILED = BASE + 3; 1697d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1707d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int SERVICE_FOUND = BASE + 4; 1717d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1727d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int SERVICE_LOST = BASE + 5; 1737d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 1747d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1757d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int STOP_DISCOVERY = BASE + 6; 1767d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1777d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int STOP_DISCOVERY_FAILED = BASE + 7; 1787d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1797d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int STOP_DISCOVERY_SUCCEEDED = BASE + 8; 1807d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 1817d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1827d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int REGISTER_SERVICE = BASE + 9; 1837d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1847d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int REGISTER_SERVICE_FAILED = BASE + 10; 1857d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1867d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int REGISTER_SERVICE_SUCCEEDED = BASE + 11; 1877d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 1887d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 18992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff public static final int UNREGISTER_SERVICE = BASE + 12; 1907d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 19192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff public static final int UNREGISTER_SERVICE_FAILED = BASE + 13; 1927d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 19392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff public static final int UNREGISTER_SERVICE_SUCCEEDED = BASE + 14; 1947d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 1957d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 19692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff public static final int RESOLVE_SERVICE = BASE + 18; 197817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff /** @hide */ 19892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff public static final int RESOLVE_SERVICE_FAILED = BASE + 19; 199817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff /** @hide */ 20092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 20; 201817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff 20292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff /** @hide */ 2033ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff public static final int ENABLE = BASE + 24; 2043ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff /** @hide */ 2053ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff public static final int DISABLE = BASE + 25; 2063ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff 20722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff /** @hide */ 20822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public static final int NATIVE_DAEMON_EVENT = BASE + 26; 20922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 21022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff /** Dns based service discovery protocol */ 21122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public static final int PROTOCOL_DNS_SD = 0x0001; 21222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 21322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private Context mContext; 21422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 21522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private static final int INVALID_LISTENER_KEY = 0; 21622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private int mListenerKey = 1; 21722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private final SparseArray mListenerMap = new SparseArray(); 21822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<NsdServiceInfo>(); 21922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private final Object mMapLock = new Object(); 22022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 22122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private final AsyncChannel mAsyncChannel = new AsyncChannel(); 22222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private ServiceHandler mHandler; 22322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private final CountDownLatch mConnected = new CountDownLatch(1); 2243ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff 2257d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** 2267d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Create a new Nsd instance. Applications use 2277d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve 2287d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * {@link android.content.Context#NSD_SERVICE Context.NSD_SERVICE}. 2297d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * @param service the Binder interface 2307d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * @hide - hide this because it takes in a parameter of type INsdManager, which 2317d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * is a system private class. 2327d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */ 23322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public NsdManager(Context context, INsdManager service) { 2347d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff mService = service; 23522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mContext = context; 23622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff init(); 2377d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 2387d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 2397d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** 24022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Failures are passed with {@link RegistrationListener#onRegistrationFailed}, 24122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link RegistrationListener#onUnregistrationFailed}, 24222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link DiscoveryListener#onStartDiscoveryFailed}, 24322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link DiscoveryListener#onStopDiscoveryFailed} or {@link ResolveListener#onResolveFailed}. 24422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * 2457d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Indicates that the operation failed due to an internal error. 2467d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */ 24722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public static final int FAILURE_INTERNAL_ERROR = 0; 2487d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 2497d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** 250817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff * Indicates that the operation failed because it is already active. 251817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff */ 25222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public static final int FAILURE_ALREADY_ACTIVE = 3; 253817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff 254817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff /** 25522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Indicates that the operation failed because the maximum outstanding 25622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * requests from the applications have reached. 257817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff */ 25822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public static final int FAILURE_MAX_LIMIT = 4; 2597d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 26022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff /** Interface for callback invocation for service discovery */ 26122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public interface DiscoveryListener { 2627d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 26322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onStartDiscoveryFailed(String serviceType, int errorCode); 2647d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 26522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onStopDiscoveryFailed(String serviceType, int errorCode); 2667d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 26722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onDiscoveryStarted(String serviceType); 2687d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 26922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onDiscoveryStopped(String serviceType); 2707d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 27122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onServiceFound(NsdServiceInfo serviceInfo); 2727d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 27322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onServiceLost(NsdServiceInfo serviceInfo); 2747d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 2757d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 2767d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 27792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff /** Interface for callback invocation for service registration */ 27822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public interface RegistrationListener { 2797d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 28022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode); 2817d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 28222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode); 2837d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 28422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onServiceRegistered(NsdServiceInfo serviceInfo); 2857d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 28622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onServiceUnregistered(NsdServiceInfo serviceInfo); 2877d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 2887d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 28992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff /** Interface for callback invocation for service resolution */ 29022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public interface ResolveListener { 2917d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 29222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode); 2937d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 29422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onServiceResolved(NsdServiceInfo serviceInfo); 2957d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 2967d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 29722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private class ServiceHandler extends Handler { 29822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ServiceHandler(Looper looper) { 29922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff super(looper); 3007d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 3017d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 30222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff @Override 30322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void handleMessage(Message message) { 30422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff Object listener = getListener(message.arg2); 30522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff boolean listenerRemove = true; 30622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff switch (message.what) { 30722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 30822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 30922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mConnected.countDown(); 31022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 31122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: 31222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff // Ignore 31322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 31422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 31522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff Log.e(TAG, "Channel lost"); 31622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 31722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case DISCOVER_SERVICES_STARTED: 31822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff String s = ((NsdServiceInfo) message.obj).getServiceType(); 31922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((DiscoveryListener) listener).onDiscoveryStarted(s); 32022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff // Keep listener until stop discovery 32122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff listenerRemove = false; 32222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 32322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case DISCOVER_SERVICES_FAILED: 32422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((DiscoveryListener) listener).onStartDiscoveryFailed( 32522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff getNsdService(message.arg2).getServiceType(), message.arg1); 32622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 32722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case SERVICE_FOUND: 32822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((DiscoveryListener) listener).onServiceFound((NsdServiceInfo) message.obj); 32922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff // Keep listener until stop discovery 33022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff listenerRemove = false; 33122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 33222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case SERVICE_LOST: 33322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((DiscoveryListener) listener).onServiceLost((NsdServiceInfo) message.obj); 33422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff // Keep listener until stop discovery 33522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff listenerRemove = false; 33622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 33722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case STOP_DISCOVERY_FAILED: 33822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((DiscoveryListener) listener).onStopDiscoveryFailed( 33922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff getNsdService(message.arg2).getServiceType(), message.arg1); 34022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 34122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case STOP_DISCOVERY_SUCCEEDED: 34222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((DiscoveryListener) listener).onDiscoveryStopped( 34322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff getNsdService(message.arg2).getServiceType()); 34422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 34522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case REGISTER_SERVICE_FAILED: 34622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((RegistrationListener) listener).onRegistrationFailed( 34722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff getNsdService(message.arg2), message.arg1); 34822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 34922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case REGISTER_SERVICE_SUCCEEDED: 35022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((RegistrationListener) listener).onServiceRegistered( 35122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff (NsdServiceInfo) message.obj); 35222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff // Keep listener until unregister 35322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff listenerRemove = false; 35422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 35522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case UNREGISTER_SERVICE_FAILED: 35622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((RegistrationListener) listener).onUnregistrationFailed( 35722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff getNsdService(message.arg2), message.arg1); 35822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 35922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case UNREGISTER_SERVICE_SUCCEEDED: 36022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((RegistrationListener) listener).onServiceUnregistered( 36122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff getNsdService(message.arg2)); 36222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 36322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case RESOLVE_SERVICE_FAILED: 36422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((ResolveListener) listener).onResolveFailed( 36522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff getNsdService(message.arg2), message.arg1); 36622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 36722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case RESOLVE_SERVICE_SUCCEEDED: 36822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj); 36922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 37022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff default: 37122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff Log.d(TAG, "Ignored " + message); 37222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 37322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 37422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (listenerRemove) { 37522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff removeListener(message.arg2); 3767d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 3777d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 37822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 3797d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 38022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private int putListener(Object listener, NsdServiceInfo s) { 38122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (listener == null) return INVALID_LISTENER_KEY; 38222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff int key; 38322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff synchronized (mMapLock) { 38422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff do { 38522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff key = mListenerKey++; 38622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } while (key == INVALID_LISTENER_KEY); 38722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mListenerMap.put(key, listener); 38822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mServiceMap.put(key, s); 38922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 39022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff return key; 39192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff } 39292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff 39322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private Object getListener(int key) { 39422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (key == INVALID_LISTENER_KEY) return null; 39522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff synchronized (mMapLock) { 39622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff return mListenerMap.get(key); 39722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 39822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 39922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 40022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private NsdServiceInfo getNsdService(int key) { 40122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff synchronized (mMapLock) { 40222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff return mServiceMap.get(key); 40322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 40422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 40522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 40622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private void removeListener(int key) { 40722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (key == INVALID_LISTENER_KEY) return; 40822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff synchronized (mMapLock) { 40922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mListenerMap.remove(key); 41022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mServiceMap.remove(key); 41122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 41222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 4137d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 41422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private int getListenerKey(Object listener) { 41522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff synchronized (mMapLock) { 41622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff int valueIndex = mListenerMap.indexOfValue(listener); 41722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (valueIndex != -1) { 41822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff return mListenerMap.keyAt(valueIndex); 41922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 42022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 42122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff return INVALID_LISTENER_KEY; 4227d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 4237d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 42422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 4257d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** 42622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Initialize AsyncChannel 4277d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */ 42822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private void init() { 42922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff final Messenger messenger = getMessenger(); 43022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (messenger == null) throw new RuntimeException("Failed to initialize"); 43122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff HandlerThread t = new HandlerThread("NsdManager"); 43222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff t.start(); 43322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mHandler = new ServiceHandler(t.getLooper()); 43422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mAsyncChannel.connect(mContext, mHandler, messenger); 43522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff try { 43622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mConnected.await(); 43722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } catch (InterruptedException e) { 43822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff Log.e(TAG, "interrupted wait at init"); 43922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 4407d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 4417d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 4427d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** 44392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * Register a service to be discovered by other services. 44492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 44592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> The function call immediately returns after sending a request to register service 44692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * to the framework. The application is notified of a success to initiate 44722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * discovery through the callback {@link RegistrationListener#onServiceRegistered} or a failure 44822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * through {@link RegistrationListener#onRegistrationFailed}. 44992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 45022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param serviceInfo The service being registered 45122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param protocolType The service discovery protocol 45222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param listener The listener notifies of a successful registration and is used to 45322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * unregister this service through a call on {@link #unregisterService}. Cannot be null. 4547d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */ 45522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void registerService(NsdServiceInfo serviceInfo, int protocolType, 45622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff RegistrationListener listener) { 45722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (TextUtils.isEmpty(serviceInfo.getServiceName()) || 45822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff TextUtils.isEmpty(serviceInfo.getServiceType())) { 45992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff throw new IllegalArgumentException("Service name or type cannot be empty"); 46092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff } 46122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (serviceInfo.getPort() <= 0) { 46292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff throw new IllegalArgumentException("Invalid port number"); 46392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff } 46422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (listener == null) { 46522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("listener cannot be null"); 46622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 46722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (protocolType != PROTOCOL_DNS_SD) { 46822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("Unsupported protocol"); 46922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 47022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, putListener(listener, serviceInfo), 47122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff serviceInfo); 4727d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 4737d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 474817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff /** 47522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Unregister a service registered through {@link #registerService}. A successful 47622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * unregister is notified to the application with a call to 47722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link RegistrationListener#onServiceUnregistered}. 47822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * 47922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param listener This should be the listener object that was passed to 48022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link #registerService}. It identifies the service that should be unregistered 48122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * and notifies of a successful unregistration. 482817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff */ 48322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void unregisterService(RegistrationListener listener) { 48422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff int id = getListenerKey(listener); 48522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (id == INVALID_LISTENER_KEY) { 48622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("listener not registered"); 48722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 48822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (listener == null) { 48922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("listener cannot be null"); 49022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 49122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mAsyncChannel.sendMessage(UNREGISTER_SERVICE, 0, id); 4927d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 4937d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 49492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff /** 49592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * Initiate service discovery to browse for instances of a service type. Service discovery 49692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * consumes network bandwidth and will continue until the application calls 49792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * {@link #stopServiceDiscovery}. 49892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 49992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> The function call immediately returns after sending a request to start service 50092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * discovery to the framework. The application is notified of a success to initiate 50122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure 50222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * through {@link DiscoveryListener#onStartDiscoveryFailed}. 50392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 50492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> Upon successful start, application is notified when a service is found with 50522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link DiscoveryListener#onServiceFound} or when a service is lost with 50622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link DiscoveryListener#onServiceLost}. 50792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 50892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> Upon failure to start, service discovery is not active and application does 50992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * not need to invoke {@link #stopServiceDiscovery} 51092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 51192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * @param serviceType The service type being discovered. Examples include "_http._tcp" for 51292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * http services or "_ipp._tcp" for printers 51322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param protocolType The service discovery protocol 51422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param listener The listener notifies of a successful discovery and is used 51522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. 51622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Cannot be null. 51792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff */ 51822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { 51992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff if (listener == null) { 52022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("listener cannot be null"); 52192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff } 52292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff if (TextUtils.isEmpty(serviceType)) { 52322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("Service type cannot be empty"); 52492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff } 52522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 52622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (protocolType != PROTOCOL_DNS_SD) { 52722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("Unsupported protocol"); 52822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 52922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 53022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff NsdServiceInfo s = new NsdServiceInfo(); 5317d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff s.setServiceType(serviceType); 53222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, putListener(listener, s), s); 5337d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 5347d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 53592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff /** 53692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * Stop service discovery initiated with {@link #discoverServices}. An active service 53722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted} 53822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * and it stays active until the application invokes a stop service discovery. A successful 53922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * stop is notified to with a call to {@link DiscoveryListener#onDiscoveryStopped}. 54092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 54122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * <p> Upon failure to stop service discovery, application is notified through 54222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link DiscoveryListener#onStopDiscoveryFailed}. 54392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 54422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param listener This should be the listener object that was passed to {@link #discoverServices}. 54522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * It identifies the discovery that should be stopped and notifies of a successful stop. 54692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff */ 54722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void stopServiceDiscovery(DiscoveryListener listener) { 54822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff int id = getListenerKey(listener); 54922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (id == INVALID_LISTENER_KEY) { 55022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("service discovery not active on listener"); 55122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 55222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (listener == null) { 55322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("listener cannot be null"); 55422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 55522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, id); 5567d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 5577d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 55892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff /** 55992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * Resolve a discovered service. An application can resolve a service right before 56092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * establishing a connection to fetch the IP and port details on which to setup 56192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * the connection. 56292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 56322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param serviceInfo service to be resolved 56492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * @param listener to receive callback upon success or failure. Cannot be null. 56592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff */ 56622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) { 56722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (TextUtils.isEmpty(serviceInfo.getServiceName()) || 56822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff TextUtils.isEmpty(serviceInfo.getServiceType())) { 56992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff throw new IllegalArgumentException("Service name or type cannot be empty"); 57092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff } 57122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (listener == null) { 57222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("listener cannot be null"); 57322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 57422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, putListener(listener, serviceInfo), 57522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff serviceInfo); 576817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff } 577817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff 5783ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff /** Internal use only @hide */ 5793ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff public void setEnabled(boolean enabled) { 5803ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff try { 5813ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff mService.setEnabled(enabled); 5823ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff } catch (RemoteException e) { } 5833ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff } 5843ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff 5857d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** 5867d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Get a reference to NetworkService handler. This is used to establish 5877d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * an AsyncChannel communication with the service 5887d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * 5897d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * @return Messenger pointing to the NetworkService handler 5907d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */ 5917d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff private Messenger getMessenger() { 5927d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff try { 5937d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff return mService.getMessenger(); 5947d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } catch (RemoteException e) { 5957d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff return null; 5967d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 5977d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 5987d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff} 599