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