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; 20d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkeyimport android.annotation.SystemService; 213ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriffimport android.annotation.SdkConstant.SdkConstantType; 227d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.content.Context; 237d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Handler; 2422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriffimport android.os.HandlerThread; 257d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Looper; 267d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Message; 277d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.RemoteException; 287d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Messenger; 2992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriffimport android.text.TextUtils; 307d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.util.Log; 3122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriffimport android.util.SparseArray; 3222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 3322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriffimport java.util.concurrent.CountDownLatch; 347d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 357d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport com.android.internal.util.AsyncChannel; 367d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport com.android.internal.util.Protocol; 377d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 387d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff/** 3992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * The Network Service Discovery Manager class provides the API to discover services 4092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * on a network. As an example, if device A and device B are connected over a Wi-Fi 4192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * network, a game registered on device A can be discovered by a game on device 4292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * B. Another example use case is an application discovering printers on the network. 4392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 4492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> The API currently supports DNS based service discovery and discovery is currently 4522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * limited to a local network over Multicast DNS. DNS service discovery is described at 4622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt 477d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * 487d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * <p> The API is asynchronous and responses to requests from an application are on listener 49fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi * callbacks on a seperate internal thread. 5092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 5192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> There are three main operations the API supports - registration, discovery and resolution. 5292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <pre> 5392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * Application start 5492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * | 5522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 5622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | onServiceRegistered() 5722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Register any local services / 5822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * to be advertised with \ 5922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * registerService() onRegistrationFailed() 6022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 6122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 6222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * discoverServices() 6322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 6422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Maintain a list to track 6522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * discovered services 6622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 6722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * |---------> 6822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | | 6922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | onServiceFound() 7022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | | 7122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | add service to list 7222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | | 7322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * |<---------- 7422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 7522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * |---------> 7622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | | 7722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | onServiceLost() 7822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | | 7922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | remove service from list 8022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | | 8122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * |<---------- 8222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 8322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 8422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | Connect to a service 8522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | from list ? 8622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 8722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * resolveService() 8822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 8922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * onServiceResolved() 9022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * | 9122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Establish connection to service 9222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * with the host and port information 9392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 9492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * </pre> 9592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * An application that needs to advertise itself over a network for other applications to 9692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * discover it can do so with a call to {@link #registerService}. If Example is a http based 9792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * application that can provide HTML data to peer services, it can register a name "Example" 9892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * with service type "_http._tcp". A successful registration is notified with a callback to 9922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link RegistrationListener#onServiceRegistered} and a failure to register is notified 10022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * over {@link RegistrationListener#onRegistrationFailed} 10192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 10292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> A peer application looking for http services can initiate a discovery for "_http._tcp" 10392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * with a call to {@link #discoverServices}. A service found is notified with a callback 10422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * to {@link DiscoveryListener#onServiceFound} and a service lost is notified on 10522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link DiscoveryListener#onServiceLost}. 10692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 1077d5da4b044183826ac8388c8bdb94ac979a81797Philip P. Moltmann * <p> Once the peer application discovers the "Example" http service, and either needs to read the 1087d5da4b044183826ac8388c8bdb94ac979a81797Philip P. Moltmann * attributes of the service or wants to receive data from the "Example" application, it can 1097d5da4b044183826ac8388c8bdb94ac979a81797Philip P. Moltmann * initiate a resolve with {@link #resolveService} to resolve the attributes, host, and port 1107d5da4b044183826ac8388c8bdb94ac979a81797Philip P. Moltmann * details. A successful resolve is notified on {@link ResolveListener#onServiceResolved} and a 1117d5da4b044183826ac8388c8bdb94ac979a81797Philip P. Moltmann * failure is notified on {@link ResolveListener#onResolveFailed}. 1127d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * 11392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * Applications can reserve for a service type at 11492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * http://www.iana.org/form/ports-service. Existing services can be found at 11592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml 1167d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * 11722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@see NsdServiceInfo} 1187d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */ 119d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkey@SystemService(Context.NSD_SERVICE) 12022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriffpublic final class NsdManager { 121fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi private static final String TAG = NsdManager.class.getSimpleName(); 122fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi private static final boolean DBG = false; 1237d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 1243ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff /** 1253ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * Broadcast intent action to indicate whether network service discovery is 1263ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * enabled or disabled. An extra {@link #EXTRA_NSD_STATE} provides the state 1273ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * information as int. 1283ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * 1293ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * @see #EXTRA_NSD_STATE 1303ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff */ 1313ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 132fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi public static final String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED"; 1333ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff 1343ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff /** 1353ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * The lookup key for an int that indicates whether network service discovery is enabled 1363ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * or disabled. Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}. 1373ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * 1383ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * @see #NSD_STATE_DISABLED 1393ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * @see #NSD_STATE_ENABLED 1403ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff */ 1413ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff public static final String EXTRA_NSD_STATE = "nsd_state"; 1423ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff 1433ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff /** 1443ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * Network service discovery is disabled 1453ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * 14654ac7a510245e5f00c16ff5595b6ae8d002c1c3bIrfan Sheriff * @see #ACTION_NSD_STATE_CHANGED 1473ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff */ 1483ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff public static final int NSD_STATE_DISABLED = 1; 1493ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff 1503ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff /** 1513ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * Network service discovery is enabled 1523ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff * 15354ac7a510245e5f00c16ff5595b6ae8d002c1c3bIrfan Sheriff * @see #ACTION_NSD_STATE_CHANGED 1543ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff */ 1553ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff public static final int NSD_STATE_ENABLED = 2; 1563ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff 1577d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff private static final int BASE = Protocol.BASE_NSD_MANAGER; 1587d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 1597d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1607d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int DISCOVER_SERVICES = BASE + 1; 1617d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1627d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int DISCOVER_SERVICES_STARTED = BASE + 2; 1637d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1647d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int DISCOVER_SERVICES_FAILED = BASE + 3; 1657d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1667d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int SERVICE_FOUND = BASE + 4; 1677d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1687d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int SERVICE_LOST = BASE + 5; 1697d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 1707d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1717d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int STOP_DISCOVERY = BASE + 6; 1727d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1737d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int STOP_DISCOVERY_FAILED = BASE + 7; 1747d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1757d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int STOP_DISCOVERY_SUCCEEDED = BASE + 8; 1767d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 1777d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1787d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int REGISTER_SERVICE = BASE + 9; 1797d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1807d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int REGISTER_SERVICE_FAILED = BASE + 10; 1817d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 1827d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff public static final int REGISTER_SERVICE_SUCCEEDED = BASE + 11; 1837d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 1847d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 18592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff public static final int UNREGISTER_SERVICE = BASE + 12; 1867d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 18792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff public static final int UNREGISTER_SERVICE_FAILED = BASE + 13; 1887d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 18992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff public static final int UNREGISTER_SERVICE_SUCCEEDED = BASE + 14; 1907d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 1917d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** @hide */ 19292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff public static final int RESOLVE_SERVICE = BASE + 18; 193817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff /** @hide */ 19492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff public static final int RESOLVE_SERVICE_FAILED = BASE + 19; 195817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff /** @hide */ 19692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 20; 197817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff 19892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff /** @hide */ 1993ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff public static final int ENABLE = BASE + 24; 2003ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff /** @hide */ 2013ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff public static final int DISABLE = BASE + 25; 2023ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff 20322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff /** @hide */ 20422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public static final int NATIVE_DAEMON_EVENT = BASE + 26; 20522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 20622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff /** Dns based service discovery protocol */ 20722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public static final int PROTOCOL_DNS_SD = 0x0001; 20822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 209fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi private static final SparseArray<String> EVENT_NAMES = new SparseArray<>(); 210fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi static { 211fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(DISCOVER_SERVICES, "DISCOVER_SERVICES"); 212fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(DISCOVER_SERVICES_STARTED, "DISCOVER_SERVICES_STARTED"); 213fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(DISCOVER_SERVICES_FAILED, "DISCOVER_SERVICES_FAILED"); 214fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND"); 215fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(SERVICE_LOST, "SERVICE_LOST"); 216fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(STOP_DISCOVERY, "STOP_DISCOVERY"); 217fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(STOP_DISCOVERY_FAILED, "STOP_DISCOVERY_FAILED"); 218fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(STOP_DISCOVERY_SUCCEEDED, "STOP_DISCOVERY_SUCCEEDED"); 219fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(REGISTER_SERVICE, "REGISTER_SERVICE"); 220fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(REGISTER_SERVICE_FAILED, "REGISTER_SERVICE_FAILED"); 221fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(REGISTER_SERVICE_SUCCEEDED, "REGISTER_SERVICE_SUCCEEDED"); 222fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(UNREGISTER_SERVICE, "UNREGISTER_SERVICE"); 223fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(UNREGISTER_SERVICE_FAILED, "UNREGISTER_SERVICE_FAILED"); 224fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(UNREGISTER_SERVICE_SUCCEEDED, "UNREGISTER_SERVICE_SUCCEEDED"); 225fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(RESOLVE_SERVICE, "RESOLVE_SERVICE"); 226fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(RESOLVE_SERVICE_FAILED, "RESOLVE_SERVICE_FAILED"); 227fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(RESOLVE_SERVICE_SUCCEEDED, "RESOLVE_SERVICE_SUCCEEDED"); 228fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(ENABLE, "ENABLE"); 229fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(DISABLE, "DISABLE"); 230fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi EVENT_NAMES.put(NATIVE_DAEMON_EVENT, "NATIVE_DAEMON_EVENT"); 231fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi } 232fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi 233fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi /** @hide */ 234fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi public static String nameOf(int event) { 235fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi String name = EVENT_NAMES.get(event); 236fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi if (name == null) { 237fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi return Integer.toString(event); 238fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi } 239fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi return name; 240fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi } 241fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi 242fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi private final INsdManager mService; 243fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi private final Context mContext; 24422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 24522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private static final int INVALID_LISTENER_KEY = 0; 246e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt private static final int BUSY_LISTENER_KEY = -1; 24722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private int mListenerKey = 1; 24822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private final SparseArray mListenerMap = new SparseArray(); 249fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<>(); 25022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private final Object mMapLock = new Object(); 25122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 25222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private final AsyncChannel mAsyncChannel = new AsyncChannel(); 25322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private ServiceHandler mHandler; 25422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private final CountDownLatch mConnected = new CountDownLatch(1); 2553ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff 2567d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** 2577d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Create a new Nsd instance. Applications use 2587d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve 2597d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * {@link android.content.Context#NSD_SERVICE Context.NSD_SERVICE}. 2607d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * @param service the Binder interface 2617d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * @hide - hide this because it takes in a parameter of type INsdManager, which 2627d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * is a system private class. 2637d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */ 26422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public NsdManager(Context context, INsdManager service) { 2657d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff mService = service; 26622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mContext = context; 26722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff init(); 2687d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 2697d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 2707d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** 27122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Failures are passed with {@link RegistrationListener#onRegistrationFailed}, 27222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link RegistrationListener#onUnregistrationFailed}, 27322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link DiscoveryListener#onStartDiscoveryFailed}, 27422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link DiscoveryListener#onStopDiscoveryFailed} or {@link ResolveListener#onResolveFailed}. 27522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * 2767d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Indicates that the operation failed due to an internal error. 2777d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */ 27822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public static final int FAILURE_INTERNAL_ERROR = 0; 2797d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 2807d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** 281817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff * Indicates that the operation failed because it is already active. 282817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff */ 28322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public static final int FAILURE_ALREADY_ACTIVE = 3; 284817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff 285817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff /** 28622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Indicates that the operation failed because the maximum outstanding 28722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * requests from the applications have reached. 288817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff */ 28922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public static final int FAILURE_MAX_LIMIT = 4; 2907d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 29122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff /** Interface for callback invocation for service discovery */ 29222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public interface DiscoveryListener { 2937d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 29422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onStartDiscoveryFailed(String serviceType, int errorCode); 2957d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 29622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onStopDiscoveryFailed(String serviceType, int errorCode); 2977d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 29822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onDiscoveryStarted(String serviceType); 2997d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 30022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onDiscoveryStopped(String serviceType); 3017d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 30222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onServiceFound(NsdServiceInfo serviceInfo); 3037d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 30422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onServiceLost(NsdServiceInfo serviceInfo); 3057d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 3067d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 3077d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 30892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff /** Interface for callback invocation for service registration */ 30922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public interface RegistrationListener { 3107d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 31122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode); 3127d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 31322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode); 3147d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 31522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onServiceRegistered(NsdServiceInfo serviceInfo); 3167d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 31722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onServiceUnregistered(NsdServiceInfo serviceInfo); 3187d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 3197d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 32092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff /** Interface for callback invocation for service resolution */ 32122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public interface ResolveListener { 3227d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 32322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode); 3247d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 32522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void onServiceResolved(NsdServiceInfo serviceInfo); 3267d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 3277d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 32822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private class ServiceHandler extends Handler { 32922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ServiceHandler(Looper looper) { 33022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff super(looper); 3317d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 3327d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 33322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff @Override 33422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void handleMessage(Message message) { 335fb320cbdbbd10554cf6c926ee29f22f4a96010cbHugo Benichi if (DBG) Log.d(TAG, "received " + nameOf(message.what)); 33622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff switch (message.what) { 33722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 33822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 3393fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt return; 34022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: 341af2eefb70146a94dc4ae1d85ffe2b0e5e8f35a69Robert Greenwalt mConnected.countDown(); 3423fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt return; 34322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 34422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff Log.e(TAG, "Channel lost"); 3453fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt return; 3463fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt default: 34722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 3483fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt } 3493fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt Object listener = getListener(message.arg2); 3503fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt if (listener == null) { 3513fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt Log.d(TAG, "Stale key " + message.arg2); 3523fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt return; 3533fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt } 3543fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt NsdServiceInfo ns = getNsdService(message.arg2); 3553fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt switch (message.what) { 35622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case DISCOVER_SERVICES_STARTED: 3573fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt String s = getNsdServiceInfoType((NsdServiceInfo) message.obj); 35822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((DiscoveryListener) listener).onDiscoveryStarted(s); 35922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 36022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case DISCOVER_SERVICES_FAILED: 361e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt removeListener(message.arg2); 3623fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt ((DiscoveryListener) listener).onStartDiscoveryFailed(getNsdServiceInfoType(ns), 3633fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt message.arg1); 36422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 36522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case SERVICE_FOUND: 36622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((DiscoveryListener) listener).onServiceFound((NsdServiceInfo) message.obj); 36722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 36822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case SERVICE_LOST: 36922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((DiscoveryListener) listener).onServiceLost((NsdServiceInfo) message.obj); 37022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 37122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case STOP_DISCOVERY_FAILED: 372e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt removeListener(message.arg2); 3733fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt ((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns), 3743fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt message.arg1); 37522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 37622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case STOP_DISCOVERY_SUCCEEDED: 377e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt removeListener(message.arg2); 3783fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt ((DiscoveryListener) listener).onDiscoveryStopped(getNsdServiceInfoType(ns)); 37922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 38022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case REGISTER_SERVICE_FAILED: 381e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt removeListener(message.arg2); 3823fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt ((RegistrationListener) listener).onRegistrationFailed(ns, message.arg1); 38322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 38422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case REGISTER_SERVICE_SUCCEEDED: 38522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((RegistrationListener) listener).onServiceRegistered( 38622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff (NsdServiceInfo) message.obj); 38722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 38822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case UNREGISTER_SERVICE_FAILED: 389e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt removeListener(message.arg2); 3903fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt ((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1); 39122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 39222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case UNREGISTER_SERVICE_SUCCEEDED: 393e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt removeListener(message.arg2); 3943fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt ((RegistrationListener) listener).onServiceUnregistered(ns); 39522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 39622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case RESOLVE_SERVICE_FAILED: 397e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt removeListener(message.arg2); 3983fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt ((ResolveListener) listener).onResolveFailed(ns, message.arg1); 39922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 40022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff case RESOLVE_SERVICE_SUCCEEDED: 401e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt removeListener(message.arg2); 40222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff ((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj); 40322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 40422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff default: 40522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff Log.d(TAG, "Ignored " + message); 40622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff break; 40722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 4087d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 40922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 4107d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 411e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt // if the listener is already in the map, reject it. Otherwise, add it and 412e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt // return its key. 41322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private int putListener(Object listener, NsdServiceInfo s) { 41422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (listener == null) return INVALID_LISTENER_KEY; 41522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff int key; 41622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff synchronized (mMapLock) { 417e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt int valueIndex = mListenerMap.indexOfValue(listener); 418e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt if (valueIndex != -1) { 419e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt return BUSY_LISTENER_KEY; 420e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt } 42122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff do { 42222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff key = mListenerKey++; 42322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } while (key == INVALID_LISTENER_KEY); 42422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mListenerMap.put(key, listener); 42522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mServiceMap.put(key, s); 42622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 42722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff return key; 42892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff } 42992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff 43022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private Object getListener(int key) { 43122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (key == INVALID_LISTENER_KEY) return null; 43222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff synchronized (mMapLock) { 43322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff return mListenerMap.get(key); 43422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 43522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 43622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 43722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private NsdServiceInfo getNsdService(int key) { 43822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff synchronized (mMapLock) { 43922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff return mServiceMap.get(key); 44022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 44122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 44222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 44322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private void removeListener(int key) { 44422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (key == INVALID_LISTENER_KEY) return; 44522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff synchronized (mMapLock) { 44622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mListenerMap.remove(key); 44722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mServiceMap.remove(key); 44822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 44922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 4507d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 45122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private int getListenerKey(Object listener) { 45222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff synchronized (mMapLock) { 45322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff int valueIndex = mListenerMap.indexOfValue(listener); 45422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (valueIndex != -1) { 45522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff return mListenerMap.keyAt(valueIndex); 45622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 45722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 45822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff return INVALID_LISTENER_KEY; 4597d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 4607d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 4613fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt private String getNsdServiceInfoType(NsdServiceInfo s) { 4623fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt if (s == null) return "?"; 4633fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt return s.getServiceType(); 4643fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt } 4653fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt 4667d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** 46722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Initialize AsyncChannel 4687d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */ 46922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff private void init() { 47022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff final Messenger messenger = getMessenger(); 47122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (messenger == null) throw new RuntimeException("Failed to initialize"); 47222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff HandlerThread t = new HandlerThread("NsdManager"); 47322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff t.start(); 47422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mHandler = new ServiceHandler(t.getLooper()); 47522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mAsyncChannel.connect(mContext, mHandler, messenger); 47622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff try { 47722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mConnected.await(); 47822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } catch (InterruptedException e) { 47922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff Log.e(TAG, "interrupted wait at init"); 48022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 4817d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 4827d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 4837d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** 48492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * Register a service to be discovered by other services. 48592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 48692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> The function call immediately returns after sending a request to register service 487e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * to the framework. The application is notified of a successful registration 488e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * through the callback {@link RegistrationListener#onServiceRegistered} or a failure 48922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * through {@link RegistrationListener#onRegistrationFailed}. 49092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 491e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * <p> The application should call {@link #unregisterService} when the service 492e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * registration is no longer required, and/or whenever the application is stopped. 493e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * 49422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param serviceInfo The service being registered 49522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param protocolType The service discovery protocol 49622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param listener The listener notifies of a successful registration and is used to 49722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * unregister this service through a call on {@link #unregisterService}. Cannot be null. 498e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * Cannot be in use for an active service registration. 4997d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */ 50022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void registerService(NsdServiceInfo serviceInfo, int protocolType, 50122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff RegistrationListener listener) { 50222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (TextUtils.isEmpty(serviceInfo.getServiceName()) || 50322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff TextUtils.isEmpty(serviceInfo.getServiceType())) { 50492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff throw new IllegalArgumentException("Service name or type cannot be empty"); 50592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff } 50622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (serviceInfo.getPort() <= 0) { 50792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff throw new IllegalArgumentException("Invalid port number"); 50892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff } 50922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (listener == null) { 51022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("listener cannot be null"); 51122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 51222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (protocolType != PROTOCOL_DNS_SD) { 51322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("Unsupported protocol"); 51422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 515e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt int key = putListener(listener, serviceInfo); 516e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt if (key == BUSY_LISTENER_KEY) { 517e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt throw new IllegalArgumentException("listener already in use"); 518e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt } 519e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, key, serviceInfo); 5207d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 5217d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 522817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff /** 52322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * Unregister a service registered through {@link #registerService}. A successful 52422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * unregister is notified to the application with a call to 52522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link RegistrationListener#onServiceUnregistered}. 52622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * 52722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param listener This should be the listener object that was passed to 52822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link #registerService}. It identifies the service that should be unregistered 529e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * and notifies of a successful or unsuccessful unregistration via the listener 530e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * callbacks. In API versions 20 and above, the listener object may be used for 531e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * another service registration once the callback has been called. In API versions <= 19, 532e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * there is no entirely reliable way to know when a listener may be re-used, and a new 533e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * listener should be created for each service registration request. 534817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff */ 53522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void unregisterService(RegistrationListener listener) { 53622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff int id = getListenerKey(listener); 53722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (id == INVALID_LISTENER_KEY) { 53822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("listener not registered"); 53922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 54022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (listener == null) { 54122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("listener cannot be null"); 54222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 54322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mAsyncChannel.sendMessage(UNREGISTER_SERVICE, 0, id); 5447d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 5457d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 54692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff /** 54792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * Initiate service discovery to browse for instances of a service type. Service discovery 54892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * consumes network bandwidth and will continue until the application calls 54992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * {@link #stopServiceDiscovery}. 55092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 55192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> The function call immediately returns after sending a request to start service 55292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * discovery to the framework. The application is notified of a success to initiate 55322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure 55422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * through {@link DiscoveryListener#onStartDiscoveryFailed}. 55592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 55692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> Upon successful start, application is notified when a service is found with 55722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link DiscoveryListener#onServiceFound} or when a service is lost with 55822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link DiscoveryListener#onServiceLost}. 55992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 56092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> Upon failure to start, service discovery is not active and application does 56192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * not need to invoke {@link #stopServiceDiscovery} 56292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 563e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * <p> The application should call {@link #stopServiceDiscovery} when discovery of this 564e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * service type is no longer required, and/or whenever the application is paused or 565e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * stopped. 566e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * 56792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * @param serviceType The service type being discovered. Examples include "_http._tcp" for 56892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * http services or "_ipp._tcp" for printers 56922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param protocolType The service discovery protocol 57022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param listener The listener notifies of a successful discovery and is used 57122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. 572e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * Cannot be null. Cannot be in use for an active service discovery. 57392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff */ 57422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { 57592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff if (listener == null) { 57622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("listener cannot be null"); 57792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff } 57892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff if (TextUtils.isEmpty(serviceType)) { 57922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("Service type cannot be empty"); 58092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff } 58122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 58222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (protocolType != PROTOCOL_DNS_SD) { 58322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("Unsupported protocol"); 58422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 58522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff 58622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff NsdServiceInfo s = new NsdServiceInfo(); 5877d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff s.setServiceType(serviceType); 588e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt 589e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt int key = putListener(listener, s); 590e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt if (key == BUSY_LISTENER_KEY) { 591e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt throw new IllegalArgumentException("listener already in use"); 592e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt } 593e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt 594e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, key, s); 5957d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 5967d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 59792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff /** 598e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * Stop service discovery initiated with {@link #discoverServices}. An active service 59922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted} 60022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * and it stays active until the application invokes a stop service discovery. A successful 60122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * stop is notified to with a call to {@link DiscoveryListener#onDiscoveryStopped}. 60292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 60322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * <p> Upon failure to stop service discovery, application is notified through 60422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link DiscoveryListener#onStopDiscoveryFailed}. 60592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 60622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param listener This should be the listener object that was passed to {@link #discoverServices}. 607e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * It identifies the discovery that should be stopped and notifies of a successful or 608e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * unsuccessful stop. In API versions 20 and above, the listener object may be used for 609e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * another service discovery once the callback has been called. In API versions <= 19, 610e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * there is no entirely reliable way to know when a listener may be re-used, and a new 611e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * listener should be created for each service discovery request. 61292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff */ 61322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void stopServiceDiscovery(DiscoveryListener listener) { 61422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff int id = getListenerKey(listener); 61522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (id == INVALID_LISTENER_KEY) { 61622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("service discovery not active on listener"); 61722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 61822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (listener == null) { 61922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("listener cannot be null"); 62022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 62122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, id); 6227d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 6237d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff 62492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff /** 62592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * Resolve a discovered service. An application can resolve a service right before 62692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * establishing a connection to fetch the IP and port details on which to setup 62792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * the connection. 62892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * 62922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * @param serviceInfo service to be resolved 63092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * @param listener to receive callback upon success or failure. Cannot be null. 631e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt * Cannot be in use for an active service resolution. 63292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff */ 63322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) { 63422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (TextUtils.isEmpty(serviceInfo.getServiceName()) || 63522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff TextUtils.isEmpty(serviceInfo.getServiceType())) { 63692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff throw new IllegalArgumentException("Service name or type cannot be empty"); 63792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff } 63822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff if (listener == null) { 63922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff throw new IllegalArgumentException("listener cannot be null"); 64022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff } 641e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt 642e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt int key = putListener(listener, serviceInfo); 643e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt 644e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt if (key == BUSY_LISTENER_KEY) { 645e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt throw new IllegalArgumentException("listener already in use"); 646e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt } 647e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, key, serviceInfo); 648817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff } 649817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff 6503ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff /** Internal use only @hide */ 6513ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff public void setEnabled(boolean enabled) { 6523ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff try { 6533ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff mService.setEnabled(enabled); 654c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey } catch (RemoteException e) { 655c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey throw e.rethrowFromSystemServer(); 656c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey } 6573ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff } 6583ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff 6597d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff /** 6607d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Get a reference to NetworkService handler. This is used to establish 6617d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * an AsyncChannel communication with the service 6627d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * 6637d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * @return Messenger pointing to the NetworkService handler 6647d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */ 6657d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff private Messenger getMessenger() { 6667d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff try { 6677d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff return mService.getMessenger(); 6687d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } catch (RemoteException e) { 669c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey throw e.rethrowFromSystemServer(); 6707d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 6717d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff } 6727d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff} 673