17d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff/*
27d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Copyright (C) 2012 The Android Open Source Project
37d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff *
47d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Licensed under the Apache License, Version 2.0 (the "License");
57d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * you may not use this file except in compliance with the License.
67d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * You may obtain a copy of the License at
77d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff *
87d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff *      http://www.apache.org/licenses/LICENSE-2.0
97d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff *
107d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Unless required by applicable law or agreed to in writing, software
117d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * distributed under the License is distributed on an "AS IS" BASIS,
127d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * See the License for the specific language governing permissions and
147d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * limitations under the License.
157d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */
167d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
177d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffpackage android.net.nsd;
187d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
193ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriffimport android.annotation.SdkConstant;
203ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriffimport android.annotation.SdkConstant.SdkConstantType;
217d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.content.Context;
227d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Handler;
2322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriffimport android.os.HandlerThread;
247d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Looper;
257d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Message;
267d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.RemoteException;
277d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.os.Messenger;
2892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriffimport android.text.TextUtils;
297d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport android.util.Log;
3022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriffimport android.util.SparseArray;
3122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
3222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriffimport java.util.concurrent.CountDownLatch;
337d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
347d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport com.android.internal.util.AsyncChannel;
357d024d372431effc87168afdc7cbe387680c4935Irfan Sheriffimport com.android.internal.util.Protocol;
367d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
377d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff/**
3892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * The Network Service Discovery Manager class provides the API to discover services
3992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * on a network. As an example, if device A and device B are connected over a Wi-Fi
4092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * network, a game registered on device A can be discovered by a game on device
4192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * B. Another example use case is an application discovering printers on the network.
4292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff *
4392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> The API currently supports DNS based service discovery and discovery is currently
4422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * limited to a local network over Multicast DNS. DNS service discovery is described at
4522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt
467d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff *
477d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * <p> The API is asynchronous and responses to requests from an application are on listener
4822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * callbacks on a seperate thread.
4992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff *
5092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> There are three main operations the API supports - registration, discovery and resolution.
5192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <pre>
5292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff *                          Application start
5392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff *                                 |
5422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |
5522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |                  onServiceRegistered()
5622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                     Register any local services  /
5722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                      to be advertised with       \
5822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                       registerService()            onRegistrationFailed()
5922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |
6022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |
6122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                          discoverServices()
6222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |
6322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                      Maintain a list to track
6422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                        discovered services
6522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |
6622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |--------->
6722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |          |
6822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |      onServiceFound()
6922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |          |
7022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |     add service to list
7122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |          |
7222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |<----------
7322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |
7422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |--------->
7522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |          |
7622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |      onServiceLost()
7722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |          |
7822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |   remove service from list
7922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |          |
8022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |<----------
8122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |
8222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |
8322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 | Connect to a service
8422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 | from list ?
8522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |
8622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                          resolveService()
8722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |
8822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                         onServiceResolved()
8922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                                 |
9022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                     Establish connection to service
9122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff *                     with the host and port information
9292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff *
9392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * </pre>
9492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * An application that needs to advertise itself over a network for other applications to
9592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * discover it can do so with a call to {@link #registerService}. If Example is a http based
9692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * application that can provide HTML data to peer services, it can register a name "Example"
9792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * with service type "_http._tcp". A successful registration is notified with a callback to
9822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link RegistrationListener#onServiceRegistered} and a failure to register is notified
9922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * over {@link RegistrationListener#onRegistrationFailed}
10092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff *
10192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> A peer application looking for http services can initiate a discovery for "_http._tcp"
10292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * with a call to {@link #discoverServices}. A service found is notified with a callback
10322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * to {@link DiscoveryListener#onServiceFound} and a service lost is notified on
10422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@link DiscoveryListener#onServiceLost}.
10592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff *
10692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * <p> Once the peer application discovers the "Example" http srevice, and needs to receive data
10792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * from the "Example" application, it can initiate a resolve with {@link #resolveService} to
10892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * resolve the host and port details for the purpose of establishing a connection. A successful
10922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * resolve is notified on {@link ResolveListener#onServiceResolved} and a failure is notified
11022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * on {@link ResolveListener#onResolveFailed}.
1117d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff *
11292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * Applications can reserve for a service type at
11392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * http://www.iana.org/form/ports-service. Existing services can be found at
11492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff * http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml
1157d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff *
1167d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Get an instance of this class by calling {@link android.content.Context#getSystemService(String)
1177d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff * Context.getSystemService(Context.NSD_SERVICE)}.
1187d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff *
11922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff * {@see NsdServiceInfo}
1207d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff */
12122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriffpublic final class NsdManager {
1227d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    private static final String TAG = "NsdManager";
1237d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    INsdManager mService;
1247d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
1253ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    /**
1263ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     * Broadcast intent action to indicate whether network service discovery is
1273ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     * enabled or disabled. An extra {@link #EXTRA_NSD_STATE} provides the state
1283ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     * information as int.
1293ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     *
1303ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     * @see #EXTRA_NSD_STATE
1313ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     */
1323ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1336c07ba8183edc593527335238a2c6083392df7bcIrfan Sheriff    public static final String ACTION_NSD_STATE_CHANGED =
1343ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        "android.net.nsd.STATE_CHANGED";
1353ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
1363ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    /**
1373ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     * The lookup key for an int that indicates whether network service discovery is enabled
1383ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     * or disabled. Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}.
1393ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     *
1403ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     * @see #NSD_STATE_DISABLED
1413ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     * @see #NSD_STATE_ENABLED
1423ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     */
1433ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    public static final String EXTRA_NSD_STATE = "nsd_state";
1443ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
1453ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    /**
1463ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     * Network service discovery is disabled
1473ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     *
14854ac7a510245e5f00c16ff5595b6ae8d002c1c3bIrfan Sheriff     * @see #ACTION_NSD_STATE_CHANGED
1493ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     */
1503ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    public static final int NSD_STATE_DISABLED = 1;
1513ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
1523ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    /**
1533ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     * Network service discovery is enabled
1543ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     *
15554ac7a510245e5f00c16ff5595b6ae8d002c1c3bIrfan Sheriff     * @see #ACTION_NSD_STATE_CHANGED
1563ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff     */
1573ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    public static final int NSD_STATE_ENABLED = 2;
1583ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
1597d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    private static final int BASE = Protocol.BASE_NSD_MANAGER;
1607d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
1617d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
1627d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    public static final int DISCOVER_SERVICES                       = BASE + 1;
1637d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
1647d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    public static final int DISCOVER_SERVICES_STARTED               = BASE + 2;
1657d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
1667d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    public static final int DISCOVER_SERVICES_FAILED                = BASE + 3;
1677d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
1687d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    public static final int SERVICE_FOUND                           = BASE + 4;
1697d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
1707d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    public static final int SERVICE_LOST                            = BASE + 5;
1717d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
1727d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
1737d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    public static final int STOP_DISCOVERY                          = BASE + 6;
1747d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
1757d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    public static final int STOP_DISCOVERY_FAILED                   = BASE + 7;
1767d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
1777d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    public static final int STOP_DISCOVERY_SUCCEEDED                = BASE + 8;
1787d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
1797d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
1807d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    public static final int REGISTER_SERVICE                        = BASE + 9;
1817d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
1827d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    public static final int REGISTER_SERVICE_FAILED                 = BASE + 10;
1837d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
1847d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    public static final int REGISTER_SERVICE_SUCCEEDED              = BASE + 11;
1857d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
1867d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
18792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff    public static final int UNREGISTER_SERVICE                      = BASE + 12;
1887d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
18992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff    public static final int UNREGISTER_SERVICE_FAILED               = BASE + 13;
1907d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
19192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff    public static final int UNREGISTER_SERVICE_SUCCEEDED            = BASE + 14;
1927d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
1937d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /** @hide */
19492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff    public static final int RESOLVE_SERVICE                         = BASE + 18;
195817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    /** @hide */
19692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff    public static final int RESOLVE_SERVICE_FAILED                  = BASE + 19;
197817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    /** @hide */
19892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff    public static final int RESOLVE_SERVICE_SUCCEEDED               = BASE + 20;
199817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
20092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff    /** @hide */
2013ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    public static final int ENABLE                                  = BASE + 24;
2023ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    /** @hide */
2033ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    public static final int DISABLE                                 = BASE + 25;
2043ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
20522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    /** @hide */
20622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    public static final int NATIVE_DAEMON_EVENT                     = BASE + 26;
20722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
20822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    /** Dns based service discovery protocol */
20922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    public static final int PROTOCOL_DNS_SD = 0x0001;
21022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
21122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private Context mContext;
21222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
21322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private static final int INVALID_LISTENER_KEY = 0;
214e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt    private static final int BUSY_LISTENER_KEY = -1;
21522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private int mListenerKey = 1;
21622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private final SparseArray mListenerMap = new SparseArray();
21722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<NsdServiceInfo>();
21822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private final Object mMapLock = new Object();
21922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
22022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private final AsyncChannel mAsyncChannel = new AsyncChannel();
22122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private ServiceHandler mHandler;
22222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private final CountDownLatch mConnected = new CountDownLatch(1);
2233ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
2247d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /**
2257d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     * Create a new Nsd instance. Applications use
2267d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
2277d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     * {@link android.content.Context#NSD_SERVICE Context.NSD_SERVICE}.
2287d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     * @param service the Binder interface
2297d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     * @hide - hide this because it takes in a parameter of type INsdManager, which
2307d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     * is a system private class.
2317d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     */
23222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    public NsdManager(Context context, INsdManager service) {
2337d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        mService = service;
23422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        mContext = context;
23522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        init();
2367d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
2377d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
2387d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /**
23922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * Failures are passed with {@link RegistrationListener#onRegistrationFailed},
24022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * {@link RegistrationListener#onUnregistrationFailed},
24122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * {@link DiscoveryListener#onStartDiscoveryFailed},
24222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * {@link DiscoveryListener#onStopDiscoveryFailed} or {@link ResolveListener#onResolveFailed}.
24322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     *
2447d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     * Indicates that the operation failed due to an internal error.
2457d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     */
24622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    public static final int FAILURE_INTERNAL_ERROR               = 0;
2477d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
2487d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /**
249817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff     * Indicates that the operation failed because it is already active.
250817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff     */
25122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    public static final int FAILURE_ALREADY_ACTIVE              = 3;
252817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
253817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    /**
25422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * Indicates that the operation failed because the maximum outstanding
25522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * requests from the applications have reached.
256817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff     */
25722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    public static final int FAILURE_MAX_LIMIT                   = 4;
2587d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
25922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    /** Interface for callback invocation for service discovery */
26022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    public interface DiscoveryListener {
2617d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
26222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        public void onStartDiscoveryFailed(String serviceType, int errorCode);
2637d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
26422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        public void onStopDiscoveryFailed(String serviceType, int errorCode);
2657d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
26622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        public void onDiscoveryStarted(String serviceType);
2677d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
26822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        public void onDiscoveryStopped(String serviceType);
2697d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
27022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        public void onServiceFound(NsdServiceInfo serviceInfo);
2717d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
27222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        public void onServiceLost(NsdServiceInfo serviceInfo);
2737d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
2747d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
2757d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
27692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff    /** Interface for callback invocation for service registration */
27722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    public interface RegistrationListener {
2787d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
27922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode);
2807d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
28122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode);
2827d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
28322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        public void onServiceRegistered(NsdServiceInfo serviceInfo);
2847d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
28522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        public void onServiceUnregistered(NsdServiceInfo serviceInfo);
2867d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
2877d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
28892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff    /** Interface for callback invocation for service resolution */
28922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    public interface ResolveListener {
2907d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
29122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode);
2927d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
29322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        public void onServiceResolved(NsdServiceInfo serviceInfo);
2947d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
2957d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
29622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private class ServiceHandler extends Handler {
29722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        ServiceHandler(Looper looper) {
29822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            super(looper);
2997d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        }
3007d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
30122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        @Override
30222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        public void handleMessage(Message message) {
30322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            switch (message.what) {
30422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
30522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
3063fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                    return;
30722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
308af2eefb70146a94dc4ae1d85ffe2b0e5e8f35a69Robert Greenwalt                    mConnected.countDown();
3093fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                    return;
31022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
31122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    Log.e(TAG, "Channel lost");
3123fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                    return;
3133fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                default:
31422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    break;
3153fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt            }
3163fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt            Object listener = getListener(message.arg2);
3173fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt            if (listener == null) {
3183fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                Log.d(TAG, "Stale key " + message.arg2);
3193fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                return;
3203fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt            }
3213fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt            NsdServiceInfo ns = getNsdService(message.arg2);
3223fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt            switch (message.what) {
32322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case DISCOVER_SERVICES_STARTED:
3243fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                    String s = getNsdServiceInfoType((NsdServiceInfo) message.obj);
32522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    ((DiscoveryListener) listener).onDiscoveryStarted(s);
32622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    break;
32722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case DISCOVER_SERVICES_FAILED:
328e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt                    removeListener(message.arg2);
3293fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                    ((DiscoveryListener) listener).onStartDiscoveryFailed(getNsdServiceInfoType(ns),
3303fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                            message.arg1);
33122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    break;
33222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case SERVICE_FOUND:
33322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    ((DiscoveryListener) listener).onServiceFound((NsdServiceInfo) message.obj);
33422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    break;
33522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case SERVICE_LOST:
33622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    ((DiscoveryListener) listener).onServiceLost((NsdServiceInfo) message.obj);
33722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    break;
33822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case STOP_DISCOVERY_FAILED:
339e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt                    removeListener(message.arg2);
3403fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                    ((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns),
3413fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                            message.arg1);
34222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    break;
34322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case STOP_DISCOVERY_SUCCEEDED:
344e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt                    removeListener(message.arg2);
3453fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                    ((DiscoveryListener) listener).onDiscoveryStopped(getNsdServiceInfoType(ns));
34622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    break;
34722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case REGISTER_SERVICE_FAILED:
348e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt                    removeListener(message.arg2);
3493fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                    ((RegistrationListener) listener).onRegistrationFailed(ns, message.arg1);
35022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    break;
35122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case REGISTER_SERVICE_SUCCEEDED:
35222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    ((RegistrationListener) listener).onServiceRegistered(
35322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                            (NsdServiceInfo) message.obj);
35422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    break;
35522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case UNREGISTER_SERVICE_FAILED:
356e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt                    removeListener(message.arg2);
3573fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                    ((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1);
35822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    break;
35922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case UNREGISTER_SERVICE_SUCCEEDED:
360e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt                    removeListener(message.arg2);
3613fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                    ((RegistrationListener) listener).onServiceUnregistered(ns);
36222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    break;
36322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case RESOLVE_SERVICE_FAILED:
364e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt                    removeListener(message.arg2);
3653fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt                    ((ResolveListener) listener).onResolveFailed(ns, message.arg1);
36622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    break;
36722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                case RESOLVE_SERVICE_SUCCEEDED:
368e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt                    removeListener(message.arg2);
36922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    ((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj);
37022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    break;
37122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                default:
37222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    Log.d(TAG, "Ignored " + message);
37322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                    break;
37422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            }
3757d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        }
37622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    }
3777d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
378e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt    // if the listener is already in the map, reject it.  Otherwise, add it and
379e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt    // return its key.
380e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt
38122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private int putListener(Object listener, NsdServiceInfo s) {
38222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (listener == null) return INVALID_LISTENER_KEY;
38322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        int key;
38422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        synchronized (mMapLock) {
385e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt            int valueIndex = mListenerMap.indexOfValue(listener);
386e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt            if (valueIndex != -1) {
387e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt                return BUSY_LISTENER_KEY;
388e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt            }
38922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            do {
39022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                key = mListenerKey++;
39122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            } while (key == INVALID_LISTENER_KEY);
39222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            mListenerMap.put(key, listener);
39322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            mServiceMap.put(key, s);
39422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
39522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        return key;
39692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff    }
39792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff
39822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private Object getListener(int key) {
39922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (key == INVALID_LISTENER_KEY) return null;
40022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        synchronized (mMapLock) {
40122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            return mListenerMap.get(key);
40222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
40322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    }
40422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
40522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private NsdServiceInfo getNsdService(int key) {
40622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        synchronized (mMapLock) {
40722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            return mServiceMap.get(key);
40822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
40922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    }
41022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
41122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private void removeListener(int key) {
41222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (key == INVALID_LISTENER_KEY) return;
41322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        synchronized (mMapLock) {
41422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            mListenerMap.remove(key);
41522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            mServiceMap.remove(key);
41622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
41722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    }
4187d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
41922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private int getListenerKey(Object listener) {
42022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        synchronized (mMapLock) {
42122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            int valueIndex = mListenerMap.indexOfValue(listener);
42222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            if (valueIndex != -1) {
42322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                return mListenerMap.keyAt(valueIndex);
42422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            }
42522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
42622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        return INVALID_LISTENER_KEY;
4277d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
4287d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
4293fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt    private String getNsdServiceInfoType(NsdServiceInfo s) {
4303fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt        if (s == null) return "?";
4313fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt        return s.getServiceType();
4323fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt    }
4333fc376b7336cfbddbb10ce3f93a853a927f6513aDave Platt
4347d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /**
43522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * Initialize AsyncChannel
4367d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     */
43722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    private void init() {
43822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        final Messenger messenger = getMessenger();
43922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (messenger == null) throw new RuntimeException("Failed to initialize");
44022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        HandlerThread t = new HandlerThread("NsdManager");
44122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        t.start();
44222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        mHandler = new ServiceHandler(t.getLooper());
44322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        mAsyncChannel.connect(mContext, mHandler, messenger);
44422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        try {
44522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            mConnected.await();
44622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        } catch (InterruptedException e) {
44722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            Log.e(TAG, "interrupted wait at init");
44822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
4497d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
4507d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
4517d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /**
45292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * Register a service to be discovered by other services.
45392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     *
45492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * <p> The function call immediately returns after sending a request to register service
455e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * to the framework. The application is notified of a successful registration
456e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * through the callback {@link RegistrationListener#onServiceRegistered} or a failure
45722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * through {@link RegistrationListener#onRegistrationFailed}.
45892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     *
459e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * <p> The application should call {@link #unregisterService} when the service
460e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * registration is no longer required, and/or whenever the application is stopped.
461e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     *
46222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * @param serviceInfo The service being registered
46322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * @param protocolType The service discovery protocol
46422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * @param listener The listener notifies of a successful registration and is used to
46522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * unregister this service through a call on {@link #unregisterService}. Cannot be null.
466e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * Cannot be in use for an active service registration.
4677d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     */
46822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    public void registerService(NsdServiceInfo serviceInfo, int protocolType,
46922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            RegistrationListener listener) {
47022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (TextUtils.isEmpty(serviceInfo.getServiceName()) ||
47122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                TextUtils.isEmpty(serviceInfo.getServiceType())) {
47292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff            throw new IllegalArgumentException("Service name or type cannot be empty");
47392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff        }
47422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (serviceInfo.getPort() <= 0) {
47592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff            throw new IllegalArgumentException("Invalid port number");
47692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff        }
47722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (listener == null) {
47822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            throw new IllegalArgumentException("listener cannot be null");
47922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
48022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (protocolType != PROTOCOL_DNS_SD) {
48122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            throw new IllegalArgumentException("Unsupported protocol");
48222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
483e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt        int key = putListener(listener, serviceInfo);
484e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt        if (key == BUSY_LISTENER_KEY) {
485e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt            throw new IllegalArgumentException("listener already in use");
486e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt        }
487e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt        mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, key, serviceInfo);
4887d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
4897d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
490817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    /**
49122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * Unregister a service registered through {@link #registerService}. A successful
49222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * unregister is notified to the application with a call to
49322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * {@link RegistrationListener#onServiceUnregistered}.
49422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     *
49522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * @param listener This should be the listener object that was passed to
49622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * {@link #registerService}. It identifies the service that should be unregistered
497e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * and notifies of a successful or unsuccessful unregistration via the listener
498e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * callbacks.  In API versions 20 and above, the listener object may be used for
499e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * another service registration once the callback has been called.  In API versions <= 19,
500e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * there is no entirely reliable way to know when a listener may be re-used, and a new
501e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * listener should be created for each service registration request.
502817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff     */
50322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    public void unregisterService(RegistrationListener listener) {
50422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        int id = getListenerKey(listener);
50522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (id == INVALID_LISTENER_KEY) {
50622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            throw new IllegalArgumentException("listener not registered");
50722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
50822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (listener == null) {
50922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            throw new IllegalArgumentException("listener cannot be null");
51022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
51122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        mAsyncChannel.sendMessage(UNREGISTER_SERVICE, 0, id);
5127d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
5137d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
51492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff    /**
51592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * Initiate service discovery to browse for instances of a service type. Service discovery
51692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * consumes network bandwidth and will continue until the application calls
51792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * {@link #stopServiceDiscovery}.
51892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     *
51992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * <p> The function call immediately returns after sending a request to start service
52092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * discovery to the framework. The application is notified of a success to initiate
52122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure
52222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * through {@link DiscoveryListener#onStartDiscoveryFailed}.
52392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     *
52492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * <p> Upon successful start, application is notified when a service is found with
52522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * {@link DiscoveryListener#onServiceFound} or when a service is lost with
52622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * {@link DiscoveryListener#onServiceLost}.
52792784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     *
52892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * <p> Upon failure to start, service discovery is not active and application does
52992784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * not need to invoke {@link #stopServiceDiscovery}
53092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     *
531e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * <p> The application should call {@link #stopServiceDiscovery} when discovery of this
532e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * service type is no longer required, and/or whenever the application is paused or
533e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * stopped.
534e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     *
53592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * @param serviceType The service type being discovered. Examples include "_http._tcp" for
53692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * http services or "_ipp._tcp" for printers
53722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * @param protocolType The service discovery protocol
53822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * @param listener  The listener notifies of a successful discovery and is used
53922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}.
540e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * Cannot be null. Cannot be in use for an active service discovery.
54192784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     */
54222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) {
54392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff        if (listener == null) {
54422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            throw new IllegalArgumentException("listener cannot be null");
54592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff        }
54692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff        if (TextUtils.isEmpty(serviceType)) {
54722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            throw new IllegalArgumentException("Service type cannot be empty");
54892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff        }
54922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
55022af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (protocolType != PROTOCOL_DNS_SD) {
55122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            throw new IllegalArgumentException("Unsupported protocol");
55222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
55322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff
55422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        NsdServiceInfo s = new NsdServiceInfo();
5557d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        s.setServiceType(serviceType);
556e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt
557e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt        int key = putListener(listener, s);
558e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt        if (key == BUSY_LISTENER_KEY) {
559e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt            throw new IllegalArgumentException("listener already in use");
560e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt        }
561e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt
562e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt        mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, key, s);
5637d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
5647d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
56592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff    /**
566e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * Stop service discovery initiated with {@link #discoverServices}.  An active service
56722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted}
56822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * and it stays active until the application invokes a stop service discovery. A successful
56922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * stop is notified to with a call to {@link DiscoveryListener#onDiscoveryStopped}.
57092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     *
57122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * <p> Upon failure to stop service discovery, application is notified through
57222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * {@link DiscoveryListener#onStopDiscoveryFailed}.
57392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     *
57422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * @param listener This should be the listener object that was passed to {@link #discoverServices}.
575e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * It identifies the discovery that should be stopped and notifies of a successful or
576e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * unsuccessful stop.  In API versions 20 and above, the listener object may be used for
577e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * another service discovery once the callback has been called.  In API versions <= 19,
578e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * there is no entirely reliable way to know when a listener may be re-used, and a new
579e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * listener should be created for each service discovery request.
58092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     */
58122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    public void stopServiceDiscovery(DiscoveryListener listener) {
58222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        int id = getListenerKey(listener);
58322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (id == INVALID_LISTENER_KEY) {
58422af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            throw new IllegalArgumentException("service discovery not active on listener");
58522af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
58622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (listener == null) {
58722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            throw new IllegalArgumentException("listener cannot be null");
58822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
58922af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, id);
5907d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
5917d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff
59292784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff    /**
59392784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * Resolve a discovered service. An application can resolve a service right before
59492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * establishing a connection to fetch the IP and port details on which to setup
59592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * the connection.
59692784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     *
59722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff     * @param serviceInfo service to be resolved
59892784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     * @param listener to receive callback upon success or failure. Cannot be null.
599e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt     * Cannot be in use for an active service resolution.
60092784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff     */
60122af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff    public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) {
60222af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (TextUtils.isEmpty(serviceInfo.getServiceName()) ||
60322af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff                TextUtils.isEmpty(serviceInfo.getServiceType())) {
60492784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff            throw new IllegalArgumentException("Service name or type cannot be empty");
60592784670c48759c0db604ddb95c05a7b9bdebed8Irfan Sheriff        }
60622af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        if (listener == null) {
60722af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff            throw new IllegalArgumentException("listener cannot be null");
60822af38c5261d2c03796b496e6edb125327cace16Irfan Sheriff        }
609e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt
610e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt        int key = putListener(listener, serviceInfo);
611e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt
612e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt        if (key == BUSY_LISTENER_KEY) {
613e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt            throw new IllegalArgumentException("listener already in use");
614e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt        }
615e7369bd4dfa4fb3fdced5b52160a5d0209132292Dave Platt        mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, key, serviceInfo);
616817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff    }
617817388e056a5d1d0e7cd7de2c6b0c9c80617bc5fIrfan Sheriff
6183ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    /** Internal use only @hide */
6193ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    public void setEnabled(boolean enabled) {
6203ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        try {
6213ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff            mService.setEnabled(enabled);
6223ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff        } catch (RemoteException e) { }
6233ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff    }
6243ef889bf561e59561ff2c6c4b2ffb586b9c5af5cIrfan Sheriff
6257d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    /**
6267d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     * Get a reference to NetworkService handler. This is used to establish
6277d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     * an AsyncChannel communication with the service
6287d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     *
6297d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     * @return Messenger pointing to the NetworkService handler
6307d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff     */
6317d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    private Messenger getMessenger() {
6327d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        try {
6337d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff            return mService.getMessenger();
6347d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        } catch (RemoteException e) {
6357d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff            return null;
6367d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff        }
6377d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff    }
6387d024d372431effc87168afdc7cbe387680c4935Irfan Sheriff}
639