Home | History | Annotate | Download | only in nsd
      1 /*
      2  * Copyright (C) 2017 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 
     17 package com.googlecode.android_scripting.facade.net.nsd;
     18 
     19 import android.content.Context;
     20 import android.net.nsd.NsdManager;
     21 import android.net.nsd.NsdServiceInfo;
     22 
     23 import com.googlecode.android_scripting.facade.EventFacade;
     24 import com.googlecode.android_scripting.facade.FacadeManager;
     25 import com.googlecode.android_scripting.jsonrpc.JsonSerializable;
     26 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
     27 import com.googlecode.android_scripting.rpc.Rpc;
     28 import com.googlecode.android_scripting.rpc.RpcParameter;
     29 
     30 import org.json.JSONException;
     31 import org.json.JSONObject;
     32 
     33 import java.net.InetAddress;
     34 import java.net.UnknownHostException;
     35 import java.util.HashMap;
     36 import java.util.Map;
     37 
     38 /**
     39  * Facade for NsdManager - exposing mDNS utilities.
     40  */
     41 public class NsdManagerFacade extends RpcReceiver {
     42     /**
     43      * NsdServiceInfo JSON constants
     44      */
     45     private static final String NSD_SERVICE_INFO_HOST = "serviceInfoHost";
     46     private static final String NSD_SERVICE_INFO_PORT = "serviceInfoPort";
     47     private static final String NSD_SERVICE_INFO_SERVICE_NAME = "serviceInfoServiceName";
     48     private static final String NSD_SERVICE_INFO_SERVICE_TYPE = "serviceInfoServiceType";
     49 
     50     /**
     51      * RegisterationListener events/data
     52      */
     53     private static final String REG_LISTENER_EVENT = "NsdRegistrationListener";
     54 
     55     private static final String REG_LISTENER_EVENT_ON_REG_FAILED = "OnRegistrationFailed";
     56     private static final String REG_LISTENER_EVENT_ON_SERVICE_REGISTERED = "OnServiceRegistered";
     57     private static final String REG_LISTENER_EVENT_ON_SERVICE_UNREG = "OnServiceUnregistered";
     58     private static final String REG_LISTENER_EVENT_ON_UNREG_FAILED = "OnUnregistrationFailed";
     59 
     60     private static final String REG_LISTENER_DATA_ID = "id";
     61     private static final String REG_LISTENER_CALLBACK = "callback";
     62     private static final String REG_LISTENER_ERROR_CODE = "error_code";
     63 
     64     /**
     65      * DiscoveryListener events/data
     66      */
     67     private static final String DISCOVERY_LISTENER_EVENT = "NsdDiscoveryListener";
     68 
     69     private static final String DISCOVERY_LISTENER_EVENT_ON_DISCOVERY_STARTED =
     70             "OnDiscoveryStarted";
     71     private static final String DISCOVERY_LISTENER_EVENT_ON_DISCOVERY_STOPPED =
     72             "OnDiscoveryStopped";
     73     private static final String DISCOVERY_LISTENER_EVENT_ON_SERVICE_FOUND = "OnServiceFound";
     74     private static final String DISCOVERY_LISTENER_EVENT_ON_SERVICE_LOST = "OnServiceLost";
     75     private static final String DISCOVERY_LISTENER_EVENT_ON_START_DISCOVERY_FAILED =
     76             "OnStartDiscoveryFailed";
     77     private static final String DISCOVERY_LISTENER_EVENT_ON_STOP_DISCOVERY_FAILED =
     78             "OnStopDiscoveryFailed";
     79 
     80     private static final String DISCOVERY_LISTENER_DATA_ID = "id";
     81     private static final String DISCOVERY_LISTENER_DATA_CALLBACK = "callback";
     82     private static final String DISCOVERY_LISTENER_DATA_SERVICE_TYPE = "service_type";
     83     private static final String DISCOVERY_LISTENER_DATA_ERROR_CODE = "error_code";
     84 
     85     /**
     86      * ResolveListener events/data
     87      */
     88     private static final String RESOLVE_LISTENER_EVENT = "NsdResolveListener";
     89 
     90     private static final String RESOLVE_LISTENER_EVENT_ON_RESOLVE_FAIL = "OnResolveFail";
     91     private static final String RESOLVE_LISTENER_EVENT_ON_SERVICE_RESOLVED = "OnServiceResolved";
     92 
     93     private static final String RESOLVE_LISTENER_DATA_ID = "id";
     94     private static final String RESOLVE_LISTENER_DATA_CALLBACK = "callback";
     95     private static final String RESOLVE_LISTENER_DATA_ERROR_CODE = "error_code";
     96 
     97     // facade class data
     98 
     99     private final EventFacade mEventFacade;
    100 
    101     private final NsdManager mNsdManager;
    102     private final Map<String, RegistrationListener> mRegistrationListeners = new HashMap<>();
    103     private final Map<String, DiscoveryListener> mDiscoveryListeners = new HashMap<>();
    104     private final Map<String, ResolveListener> mResolveListener = new HashMap<>();
    105 
    106     private static NsdServiceInfo getNsdServiceInfo(JSONObject j)
    107             throws JSONException, UnknownHostException {
    108         if (j == null) {
    109             return null;
    110         }
    111 
    112         NsdServiceInfo nsi = new NsdServiceInfo();
    113 
    114         if (j.has(NSD_SERVICE_INFO_SERVICE_NAME)) {
    115             nsi.setServiceName(j.getString(NSD_SERVICE_INFO_SERVICE_NAME));
    116         }
    117         if (j.has(NSD_SERVICE_INFO_SERVICE_TYPE)) {
    118             nsi.setServiceType(j.getString(NSD_SERVICE_INFO_SERVICE_TYPE));
    119         }
    120         if (j.has(NSD_SERVICE_INFO_PORT)) {
    121             nsi.setPort(j.getInt(NSD_SERVICE_INFO_PORT));
    122         }
    123         if (j.has(NSD_SERVICE_INFO_HOST)) {
    124             nsi.setHost(InetAddress.getByName(j.getString(NSD_SERVICE_INFO_HOST)));
    125         }
    126 
    127         return nsi;
    128     }
    129 
    130     private static void addNsdServiceInfo(JSONObject j, NsdServiceInfo nsi) {
    131         try {
    132             j.put(NSD_SERVICE_INFO_SERVICE_NAME, nsi.getServiceName());
    133             j.put(NSD_SERVICE_INFO_SERVICE_TYPE, nsi.getServiceType());
    134             j.put(NSD_SERVICE_INFO_HOST, nsi.getHost());
    135             j.put(NSD_SERVICE_INFO_PORT, nsi.getPort());
    136         } catch (JSONException e) {
    137             throw new RuntimeException(e);
    138         }
    139     }
    140 
    141     public NsdManagerFacade(FacadeManager manager) {
    142         super(manager);
    143         mNsdManager = (NsdManager) manager.getService().getSystemService(Context.NSD_SERVICE);
    144         mEventFacade = manager.getReceiver(EventFacade.class);
    145     }
    146 
    147     @Override
    148     public void shutdown() {
    149         if (mNsdManager != null) {
    150             for (RegistrationListener listener : mRegistrationListeners.values()) {
    151                 mNsdManager.unregisterService(listener);
    152             }
    153             mRegistrationListeners.clear();
    154 
    155             for (NsdManager.DiscoveryListener listener : mDiscoveryListeners.values()) {
    156                 mNsdManager.stopServiceDiscovery(listener);
    157             }
    158             mDiscoveryListeners.clear();
    159 
    160             mResolveListener.clear();
    161         }
    162     }
    163 
    164     /**
    165      * Facade for NsdManager.registerService().
    166      */
    167     @Rpc(description = "register a service (starts advertising)")
    168     public String nsdRegisterService(
    169             @RpcParameter(name = "service information") JSONObject serviceInfo)
    170             throws JSONException, UnknownHostException {
    171         NsdServiceInfo nsi = getNsdServiceInfo(serviceInfo);
    172         RegistrationListener listener = new RegistrationListener();
    173         mRegistrationListeners.put(listener.mListenerId, listener);
    174         mNsdManager.registerService(nsi, NsdManager.PROTOCOL_DNS_SD, listener);
    175         return listener.mListenerId;
    176     }
    177 
    178     /**
    179      * Facade for NsdManager.unregisterService().
    180      */
    181     @Rpc(description = "unregister a service (stops advertising)")
    182     public Boolean nsdUnregisterService(
    183             @RpcParameter(name = "service registration callback ID") String id) {
    184         RegistrationListener listener = mRegistrationListeners.get(id);
    185         if (listener != null) {
    186             mNsdManager.unregisterService(listener);
    187             return true;
    188         } else {
    189             return false;
    190         }
    191     }
    192 
    193     /**
    194      * Facade for NsdManager.discoverServices().
    195      */
    196     @Rpc(description = "start service discovery")
    197     public String nsdDiscoverServices(@RpcParameter(name = "service type") String serviceType) {
    198         DiscoveryListener listener = new DiscoveryListener();
    199         mDiscoveryListeners.put(listener.mListenerId, listener);
    200         mNsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, listener);
    201         return listener.mListenerId;
    202     }
    203 
    204     /**
    205      * Facade for NsdManager.stopServiceDiscovery().
    206      */
    207     @Rpc(description = "stop service discovery")
    208     public Boolean nsdStopServiceDiscovery(
    209             @RpcParameter(name = "service discovery callback ID") String id) {
    210         DiscoveryListener listener = mDiscoveryListeners.get(id);
    211         if (listener != null) {
    212             mNsdManager.stopServiceDiscovery(listener);
    213             return true;
    214         } else {
    215             return false;
    216         }
    217     }
    218 
    219     /**
    220      * Facade for NsdManager.resolveService().
    221      */
    222     @Rpc(description = "resolved discovered service info")
    223     public String nsdResolveService(
    224             @RpcParameter(name = "service information") JSONObject serviceInfo)
    225             throws JSONException, UnknownHostException {
    226         ResolveListener listener = new ResolveListener();
    227         mResolveListener.put(listener.mListenerId, listener);
    228         mNsdManager.resolveService(getNsdServiceInfo(serviceInfo), listener);
    229         return listener.mListenerId;
    230     }
    231 
    232     private class RegistrationListener implements NsdManager.RegistrationListener {
    233         final String mListenerId;
    234 
    235         RegistrationListener() {
    236             mListenerId = "com.googlecode.android_scripting.facade.net.nsd.RegistrationListener: "
    237                     + System.identityHashCode(this);
    238         }
    239 
    240         @Override
    241         public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
    242             mEventFacade.postEvent(
    243                     REG_LISTENER_EVENT,
    244                     new RegistrationListenerEvent(REG_LISTENER_EVENT_ON_REG_FAILED, serviceInfo,
    245                             errorCode));
    246         }
    247 
    248         @Override
    249         public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
    250             mEventFacade.postEvent(
    251                     REG_LISTENER_EVENT,
    252                     new RegistrationListenerEvent(REG_LISTENER_EVENT_ON_UNREG_FAILED, serviceInfo,
    253                             errorCode));
    254         }
    255 
    256         @Override
    257         public void onServiceRegistered(NsdServiceInfo serviceInfo) {
    258             mEventFacade.postEvent(
    259                     REG_LISTENER_EVENT,
    260                     new RegistrationListenerEvent(REG_LISTENER_EVENT_ON_SERVICE_REGISTERED,
    261                             serviceInfo, null));
    262         }
    263 
    264         @Override
    265         public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
    266             mEventFacade.postEvent(
    267                     REG_LISTENER_EVENT,
    268                     new RegistrationListenerEvent(REG_LISTENER_EVENT_ON_SERVICE_UNREG, serviceInfo,
    269                             null));
    270         }
    271 
    272         private class RegistrationListenerEvent implements JsonSerializable {
    273             private final String mCallback;
    274             private final NsdServiceInfo mServiceInfo;
    275             private final Integer mErrorCode;
    276 
    277             RegistrationListenerEvent(String callback, NsdServiceInfo serviceInfo,
    278                     Integer errorCode) {
    279                 mCallback = callback;
    280                 mServiceInfo = serviceInfo;
    281                 mErrorCode = errorCode;
    282             }
    283 
    284             @Override
    285             public JSONObject toJSON() throws JSONException {
    286                 JSONObject j = new JSONObject();
    287 
    288                 j.put(REG_LISTENER_DATA_ID, mListenerId);
    289                 j.put(REG_LISTENER_CALLBACK, mCallback);
    290                 addNsdServiceInfo(j, mServiceInfo);
    291                 if (mErrorCode != null) {
    292                     j.put(REG_LISTENER_ERROR_CODE, mErrorCode.intValue());
    293                 }
    294 
    295                 return j;
    296             }
    297         }
    298     }
    299 
    300     private class DiscoveryListener implements NsdManager.DiscoveryListener {
    301         final String mListenerId;
    302 
    303         DiscoveryListener() {
    304             mListenerId = "com.googlecode.android_scripting.facade.net.nsd.DiscoveryListener: "
    305                     + System.identityHashCode(this);
    306         }
    307 
    308         @Override
    309         public void onStartDiscoveryFailed(String serviceType, int errorCode) {
    310             mEventFacade.postEvent(DISCOVERY_LISTENER_EVENT,
    311                     new DiscoveryListenerEvent(DISCOVERY_LISTENER_EVENT_ON_START_DISCOVERY_FAILED,
    312                             serviceType, null, errorCode));
    313         }
    314 
    315         @Override
    316         public void onStopDiscoveryFailed(String serviceType, int errorCode) {
    317             mEventFacade.postEvent(DISCOVERY_LISTENER_EVENT,
    318                     new DiscoveryListenerEvent(DISCOVERY_LISTENER_EVENT_ON_STOP_DISCOVERY_FAILED,
    319                             serviceType, null, errorCode));
    320         }
    321 
    322         @Override
    323         public void onDiscoveryStarted(String serviceType) {
    324             mEventFacade.postEvent(DISCOVERY_LISTENER_EVENT,
    325                     new DiscoveryListenerEvent(DISCOVERY_LISTENER_EVENT_ON_DISCOVERY_STARTED,
    326                             serviceType, null, null));
    327         }
    328 
    329         @Override
    330         public void onDiscoveryStopped(String serviceType) {
    331             mEventFacade.postEvent(DISCOVERY_LISTENER_EVENT,
    332                     new DiscoveryListenerEvent(DISCOVERY_LISTENER_EVENT_ON_DISCOVERY_STOPPED,
    333                             serviceType, null, null));
    334         }
    335 
    336         @Override
    337         public void onServiceFound(NsdServiceInfo serviceInfo) {
    338             mEventFacade.postEvent(DISCOVERY_LISTENER_EVENT,
    339                     new DiscoveryListenerEvent(DISCOVERY_LISTENER_EVENT_ON_SERVICE_FOUND, null,
    340                             serviceInfo, null));
    341         }
    342 
    343         @Override
    344         public void onServiceLost(NsdServiceInfo serviceInfo) {
    345             mEventFacade.postEvent(DISCOVERY_LISTENER_EVENT,
    346                     new DiscoveryListenerEvent(DISCOVERY_LISTENER_EVENT_ON_SERVICE_LOST, null,
    347                             serviceInfo, null));
    348         }
    349 
    350         private class DiscoveryListenerEvent implements JsonSerializable {
    351             private final String mCallback;
    352             private final String mServiceType;
    353             private final NsdServiceInfo mServiceInfo;
    354             private final Integer mErrorCode;
    355 
    356             DiscoveryListenerEvent(String callback, String serviceType, NsdServiceInfo serviceInfo,
    357                     Integer errorCode) {
    358                 mCallback = callback;
    359                 mServiceType = serviceType;
    360                 mServiceInfo = serviceInfo;
    361                 mErrorCode = errorCode;
    362             }
    363 
    364             @Override
    365             public JSONObject toJSON() throws JSONException {
    366                 JSONObject j = new JSONObject();
    367 
    368                 j.put(DISCOVERY_LISTENER_DATA_ID, mListenerId);
    369                 j.put(DISCOVERY_LISTENER_DATA_CALLBACK, mCallback);
    370                 if (mServiceType != null) {
    371                     j.put(DISCOVERY_LISTENER_DATA_SERVICE_TYPE, mServiceType);
    372                 }
    373                 if (mServiceInfo != null) {
    374                     addNsdServiceInfo(j, mServiceInfo);
    375                 }
    376                 if (mErrorCode != null) {
    377                     j.put(DISCOVERY_LISTENER_DATA_ERROR_CODE, mErrorCode.intValue());
    378                 }
    379 
    380                 return j;
    381             }
    382         }
    383     }
    384 
    385     private class ResolveListener implements NsdManager.ResolveListener {
    386         final String mListenerId;
    387 
    388         ResolveListener() {
    389             mListenerId = "com.googlecode.android_scripting.facade.net.nsd.ResolveListener: "
    390                     + System.identityHashCode(this);
    391         }
    392 
    393         @Override
    394         public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
    395             mEventFacade.postEvent(RESOLVE_LISTENER_EVENT,
    396                     new ResolveListenerEvent(RESOLVE_LISTENER_EVENT_ON_RESOLVE_FAIL, serviceInfo,
    397                             errorCode));
    398         }
    399 
    400         @Override
    401         public void onServiceResolved(NsdServiceInfo serviceInfo) {
    402             mEventFacade.postEvent(RESOLVE_LISTENER_EVENT,
    403                     new ResolveListenerEvent(RESOLVE_LISTENER_EVENT_ON_SERVICE_RESOLVED,
    404                             serviceInfo, null));
    405         }
    406 
    407         private class ResolveListenerEvent implements JsonSerializable {
    408             private final String mCallback;
    409             private final NsdServiceInfo mServiceInfo;
    410             private final Integer mErrorCode;
    411 
    412             ResolveListenerEvent(String callback, NsdServiceInfo serviceInfo,
    413                     Integer errorCode) {
    414                 mCallback = callback;
    415                 mServiceInfo = serviceInfo;
    416                 mErrorCode = errorCode;
    417             }
    418 
    419             @Override
    420             public JSONObject toJSON() throws JSONException {
    421                 JSONObject j = new JSONObject();
    422 
    423                 j.put(RESOLVE_LISTENER_DATA_ID, mListenerId);
    424                 j.put(RESOLVE_LISTENER_DATA_CALLBACK, mCallback);
    425                 addNsdServiceInfo(j, mServiceInfo);
    426                 if (mErrorCode != null) {
    427                     j.put(RESOLVE_LISTENER_DATA_ERROR_CODE, mErrorCode.intValue());
    428                 }
    429 
    430                 return j;
    431             }
    432         }
    433     }
    434 }
    435