NsdManager.java revision 7d024d372431effc87168afdc7cbe387680c4935
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net.nsd;
18
19import android.content.Context;
20import android.os.Binder;
21import android.os.IBinder;
22import android.os.Handler;
23import android.os.Looper;
24import android.os.Message;
25import android.os.RemoteException;
26import android.os.Messenger;
27import android.util.Log;
28
29import com.android.internal.util.AsyncChannel;
30import com.android.internal.util.Protocol;
31
32/**
33 * The Network Service Discovery Manager class provides the API for service
34 * discovery. Service discovery enables applications to discover and connect with services
35 * on a network. Example applications include a game application discovering another instance
36 * of the game application or a printer application discovering other printers on a network.
37 *
38 * <p> The API is asynchronous and responses to requests from an application are on listener
39 * callbacks provided by the application. The application needs to do an initialization with
40 * {@link #initialize} before doing any operation.
41 *
42 * <p> Android currently supports DNS based service discovery and it is limited to a local
43 * network with the use of multicast DNS. In future, this class will be
44 * extended to support other service discovery mechanisms.
45 *
46 * Get an instance of this class by calling {@link android.content.Context#getSystemService(String)
47 * Context.getSystemService(Context.NSD_SERVICE)}.
48 * @hide
49 *
50 */
51public class NsdManager {
52    private static final String TAG = "NsdManager";
53    INsdManager mService;
54
55    private static final int BASE = Protocol.BASE_NSD_MANAGER;
56
57    /** @hide */
58    public static final int DISCOVER_SERVICES                       = BASE + 1;
59    /** @hide */
60    public static final int DISCOVER_SERVICES_STARTED               = BASE + 2;
61    /** @hide */
62    public static final int DISCOVER_SERVICES_FAILED                = BASE + 3;
63    /** @hide */
64    public static final int SERVICE_FOUND                           = BASE + 4;
65    /** @hide */
66    public static final int SERVICE_LOST                            = BASE + 5;
67
68    /** @hide */
69    public static final int STOP_DISCOVERY                          = BASE + 6;
70    /** @hide */
71    public static final int STOP_DISCOVERY_FAILED                   = BASE + 7;
72    /** @hide */
73    public static final int STOP_DISCOVERY_SUCCEEDED                = BASE + 8;
74
75    /** @hide */
76    public static final int REGISTER_SERVICE                        = BASE + 9;
77    /** @hide */
78    public static final int REGISTER_SERVICE_FAILED                 = BASE + 10;
79    /** @hide */
80    public static final int REGISTER_SERVICE_SUCCEEDED              = BASE + 11;
81
82    /** @hide */
83    public static final int UPDATE_SERVICE                          = BASE + 12;
84    /** @hide */
85    public static final int UPDATE_SERVICE_FAILED                   = BASE + 13;
86    /** @hide */
87    public static final int UPDATE_SERVICE_SUCCEEDED                = BASE + 14;
88
89    /** @hide */
90    public static final int RESOLVE_SERVICE                         = BASE + 15;
91    /** @hide */
92    public static final int RESOLVE_SERVICE_FAILED                  = BASE + 16;
93    /** @hide */
94    public static final int RESOLVE_SERVICE_SUCCEEDED               = BASE + 17;
95
96    /**
97     * Create a new Nsd instance. Applications use
98     * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
99     * {@link android.content.Context#NSD_SERVICE Context.NSD_SERVICE}.
100     * @param service the Binder interface
101     * @hide - hide this because it takes in a parameter of type INsdManager, which
102     * is a system private class.
103     */
104    public NsdManager(INsdManager service) {
105        mService = service;
106    }
107
108    /**
109     * Indicates that the operation failed due to an internal error.
110     */
111    public static final int ERROR               = 0;
112
113    /**
114     * Indicates that the operation failed because service discovery is unsupported on the device.
115     */
116    public static final int UNSUPPORTED         = 1;
117
118    /**
119     * Indicates that the operation failed because the framework is busy and
120     * unable to service the request
121     */
122    public static final int BUSY                = 2;
123
124    /** Interface for callback invocation when framework channel is connected or lost */
125    public interface ChannelListener {
126        public void onChannelConnected(Channel c);
127        /**
128         * The channel to the framework has been disconnected.
129         * Application could try re-initializing using {@link #initialize}
130         */
131        public void onChannelDisconnected();
132    }
133
134    public interface ActionListener {
135
136        public void onFailure(int errorCode);
137
138        public void onSuccess();
139    }
140
141    public interface DnsSdDiscoveryListener {
142
143        public void onFailure(int errorCode);
144
145        public void onStarted(String registrationType);
146
147        public void onServiceFound(DnsSdServiceInfo serviceInfo);
148
149        public void onServiceLost(DnsSdServiceInfo serviceInfo);
150
151    }
152
153    public interface DnsSdRegisterListener {
154
155        public void onFailure(int errorCode);
156
157        public void onServiceRegistered(int registeredId, DnsSdServiceInfo serviceInfo);
158    }
159
160    public interface DnsSdUpdateRegistrationListener {
161
162        public void onFailure(int errorCode);
163
164        public void onServiceUpdated(int registeredId, DnsSdTxtRecord txtRecord);
165    }
166
167    public interface DnsSdResolveListener {
168
169        public void onFailure(int errorCode);
170
171        public void onServiceResolved(DnsSdServiceInfo serviceInfo);
172    }
173
174    /**
175     * A channel that connects the application to the NetworkService framework.
176     * Most service operations require a Channel as an argument. An instance of Channel is obtained
177     * by doing a call on {@link #initialize}
178     */
179    public static class Channel {
180        Channel(Looper looper, ChannelListener l) {
181            mAsyncChannel = new AsyncChannel();
182            mHandler = new ServiceHandler(looper);
183            mChannelListener = l;
184        }
185        private ChannelListener mChannelListener;
186        private DnsSdDiscoveryListener mDnsSdDiscoveryListener;
187        private ActionListener mDnsSdStopDiscoveryListener;
188        private DnsSdRegisterListener mDnsSdRegisterListener;
189        private DnsSdUpdateRegistrationListener mDnsSdUpdateListener;
190        private DnsSdResolveListener mDnsSdResolveListener;
191
192        AsyncChannel mAsyncChannel;
193        ServiceHandler mHandler;
194        class ServiceHandler extends Handler {
195            ServiceHandler(Looper looper) {
196                super(looper);
197            }
198
199            @Override
200            public void handleMessage(Message message) {
201                switch (message.what) {
202                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
203                        mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
204                        break;
205                    case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
206                        if (mChannelListener != null) {
207                            mChannelListener.onChannelConnected(Channel.this);
208                        }
209                        break;
210                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
211                        if (mChannelListener != null) {
212                            mChannelListener.onChannelDisconnected();
213                            mChannelListener = null;
214                        }
215                        break;
216                    case DISCOVER_SERVICES_STARTED:
217                        if (mDnsSdDiscoveryListener != null) {
218                            mDnsSdDiscoveryListener.onStarted((String) message.obj);
219                        }
220                        break;
221                    case DISCOVER_SERVICES_FAILED:
222                        if (mDnsSdDiscoveryListener != null) {
223                            mDnsSdDiscoveryListener.onFailure(message.arg1);
224                        }
225                        break;
226                    case SERVICE_FOUND:
227                        if (mDnsSdDiscoveryListener != null) {
228                            mDnsSdDiscoveryListener.onServiceFound(
229                                    (DnsSdServiceInfo) message.obj);
230                        }
231                        break;
232                    case SERVICE_LOST:
233                        if (mDnsSdDiscoveryListener != null) {
234                            mDnsSdDiscoveryListener.onServiceLost(
235                                    (DnsSdServiceInfo) message.obj);
236                        }
237                        break;
238                    case STOP_DISCOVERY_FAILED:
239                        if (mDnsSdStopDiscoveryListener != null) {
240                            mDnsSdStopDiscoveryListener.onFailure(message.arg1);
241                        }
242                        break;
243                    case STOP_DISCOVERY_SUCCEEDED:
244                        if (mDnsSdStopDiscoveryListener != null) {
245                            mDnsSdStopDiscoveryListener.onSuccess();
246                        }
247                        break;
248                    case REGISTER_SERVICE_FAILED:
249                        if (mDnsSdRegisterListener != null) {
250                            mDnsSdRegisterListener.onFailure(message.arg1);
251                        }
252                        break;
253                    case REGISTER_SERVICE_SUCCEEDED:
254                        if (mDnsSdRegisterListener != null) {
255                            mDnsSdRegisterListener.onServiceRegistered(message.arg1,
256                                    (DnsSdServiceInfo) message.obj);
257                        }
258                        break;
259                    case UPDATE_SERVICE_FAILED:
260                        if (mDnsSdUpdateListener != null) {
261                            mDnsSdUpdateListener.onFailure(message.arg1);
262                        }
263                        break;
264                    case UPDATE_SERVICE_SUCCEEDED:
265                        if (mDnsSdUpdateListener != null) {
266                            mDnsSdUpdateListener.onServiceUpdated(message.arg1,
267                                    (DnsSdTxtRecord) message.obj);
268                        }
269                        break;
270                    case RESOLVE_SERVICE_FAILED:
271                        if (mDnsSdResolveListener != null) {
272                            mDnsSdResolveListener.onFailure(message.arg1);
273                        }
274                        break;
275                    case RESOLVE_SERVICE_SUCCEEDED:
276                        if (mDnsSdResolveListener != null) {
277                            mDnsSdResolveListener.onServiceResolved(
278                                    (DnsSdServiceInfo) message.obj);
279                        }
280                        break;
281                    default:
282                        Log.d(TAG, "Ignored " + message);
283                        break;
284                }
285            }
286        }
287   }
288
289    /**
290     * Registers the application with the service discovery framework. This function
291     * must be the first to be called before any other operations are performed. No service
292     * discovery operations must be performed until the ChannelListener callback notifies
293     * that the channel is connected
294     *
295     * @param srcContext is the context of the source
296     * @param srcLooper is the Looper on which the callbacks are receivied
297     * @param listener for callback at loss of framework communication.
298     */
299    public void initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
300        Messenger messenger = getMessenger();
301        if (messenger == null) throw new RuntimeException("Failed to initialize");
302        if (listener == null) throw new IllegalArgumentException("ChannelListener cannot be null");
303
304        Channel c = new Channel(srcLooper, listener);
305        c.mAsyncChannel.connect(srcContext, c.mHandler, messenger);
306    }
307
308    /**
309     * Set the listener for service discovery. Can be null.
310     */
311    public void setDiscoveryListener(Channel c, DnsSdDiscoveryListener b) {
312        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
313        c.mDnsSdDiscoveryListener = b;
314    }
315
316    /**
317     * Set the listener for stop service discovery. Can be null.
318     */
319    public void setStopDiscoveryListener(Channel c, ActionListener a) {
320        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
321        c.mDnsSdStopDiscoveryListener = a;
322    }
323
324    /**
325     * Set the listener for service registration. Can be null.
326     */
327    public void setRegisterListener(Channel c, DnsSdRegisterListener b) {
328        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
329        c.mDnsSdRegisterListener = b;
330    }
331
332    /**
333     * Set the listener for service registration. Can be null.
334     */
335    public void setUpdateRegistrationListener(Channel c, DnsSdUpdateRegistrationListener b) {
336        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
337        c.mDnsSdUpdateListener = b;
338    }
339
340    /**
341     * Set the listener for service resolution. Can be null.
342     */
343    public void setResolveListener(Channel c, DnsSdResolveListener b) {
344        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
345        c.mDnsSdResolveListener = b;
346    }
347
348    public void registerService(Channel c, DnsSdServiceInfo serviceInfo) {
349        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
350        if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo");
351        c.mAsyncChannel.sendMessage(REGISTER_SERVICE, serviceInfo);
352    }
353
354    public void updateService(Channel c, int registeredId, DnsSdTxtRecord txtRecord) {
355        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
356        c.mAsyncChannel.sendMessage(UPDATE_SERVICE, registeredId, 0, txtRecord);
357    }
358
359    public void discoverServices(Channel c, String serviceType) {
360        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
361        if (c.mDnsSdDiscoveryListener == null) throw new
362                IllegalStateException("Discovery listener needs to be set first");
363        DnsSdServiceInfo s = new DnsSdServiceInfo();
364        s.setServiceType(serviceType);
365        c.mAsyncChannel.sendMessage(DISCOVER_SERVICES, s);
366    }
367
368    public void stopServiceDiscovery(Channel c) {
369        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
370        c.mAsyncChannel.sendMessage(STOP_DISCOVERY);
371    }
372
373    public void resolveService(Channel c, DnsSdServiceInfo serviceInfo) {
374        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
375        if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo");
376        if (c.mDnsSdResolveListener == null) throw new
377                IllegalStateException("Resolve listener needs to be set first");
378        c.mAsyncChannel.sendMessage(RESOLVE_SERVICE, serviceInfo);
379    }
380
381    /**
382     * Get a reference to NetworkService handler. This is used to establish
383     * an AsyncChannel communication with the service
384     *
385     * @return Messenger pointing to the NetworkService handler
386     */
387    private Messenger getMessenger() {
388        try {
389            return mService.getMessenger();
390        } catch (RemoteException e) {
391            return null;
392        }
393    }
394}
395