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