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