DiscoveryListenerMultiplexer.java revision bfaa47233215996b8554a4b7a1a7b36bb3eaf607
1/* 2 * Copyright (C) 2016 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 com.android.printservice.recommendation.util; 18 19import android.annotation.NonNull; 20import android.net.nsd.NsdManager; 21import android.net.nsd.NsdServiceInfo; 22import android.util.ArrayMap; 23import android.util.Log; 24 25import java.util.ArrayList; 26 27/** 28 * Used to multiplex listening for NSD services. This is needed as only a limited amount of 29 * {@link NsdManager.DiscoveryListener listeners} are allowed. 30 */ 31public class DiscoveryListenerMultiplexer { 32 private static final String LOG_TAG = "DiscoveryListenerMx"; 33 34 /** List of registered {@link DiscoveryListenerSet discovery sets}. */ 35 private static final @NonNull ArrayMap<String, DiscoveryListenerSet> sListeners = 36 new ArrayMap<>(); 37 38 /** 39 * Add a new {@link NsdManager.DiscoveryListener listener} for a {@code serviceType}. 40 * 41 * @param nsdManager The {@link NsdManager NSD manager} to use 42 * @param serviceType The service type to listen for 43 * @param newListener the {@link NsdManager.DiscoveryListener listener} to add. 44 */ 45 public static void addListener(@NonNull NsdManager nsdManager, @NonNull String serviceType, 46 @NonNull NsdManager.DiscoveryListener newListener) { 47 synchronized (sListeners) { 48 DiscoveryListenerSet listenerSet = sListeners.get(serviceType); 49 50 if (listenerSet == null) { 51 ArrayList<NsdManager.DiscoveryListener> subListeners = new ArrayList<>(1); 52 listenerSet = new DiscoveryListenerSet(subListeners, 53 new MultiListener(subListeners)); 54 55 sListeners.put(serviceType, listenerSet); 56 } 57 58 synchronized (listenerSet.subListeners) { 59 if (listenerSet.subListeners.isEmpty()) { 60 nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, 61 listenerSet.mainListener); 62 } 63 64 listenerSet.subListeners.add(newListener); 65 } 66 } 67 } 68 69 /** 70 * Remove a previously added {@link NsdManager.DiscoveryListener listener}. 71 * 72 * @param nsdManager The {@link NsdManager NSD manager} to use 73 * @param listener The {@link NsdManager.DiscoveryListener listener} that was registered 74 * 75 * @return true iff the listener was removed 76 */ 77 public static boolean removeListener(@NonNull NsdManager nsdManager, 78 @NonNull NsdManager.DiscoveryListener listener) { 79 boolean wasRemoved = false; 80 81 synchronized (sListeners) { 82 for (DiscoveryListenerSet listeners : sListeners.values()) { 83 synchronized (listeners) { 84 wasRemoved = listeners.subListeners.remove(listener); 85 86 if (wasRemoved) { 87 if (listeners.subListeners.isEmpty()) { 88 nsdManager.stopServiceDiscovery(listeners.mainListener); 89 } 90 91 break; 92 } 93 } 94 } 95 } 96 97 return wasRemoved; 98 } 99 100 /** Private class holding all data for a service type */ 101 private static class DiscoveryListenerSet { 102 /** The plugin's listeners */ 103 final @NonNull ArrayList<NsdManager.DiscoveryListener> subListeners; 104 105 /** The listener registered with the NSD Manager */ 106 final @NonNull MultiListener mainListener; 107 108 private DiscoveryListenerSet(ArrayList<NsdManager.DiscoveryListener> subListeners, 109 MultiListener mainListener) { 110 this.subListeners = subListeners; 111 this.mainListener = mainListener; 112 } 113 } 114 115 /** 116 * A {@link NsdManager.DiscoveryListener} that calls a list of registered listeners when 117 * a service is found or lost. 118 */ 119 private static class MultiListener implements NsdManager.DiscoveryListener { 120 private final @NonNull ArrayList<NsdManager.DiscoveryListener> mListeners; 121 122 /** 123 * Create a new multi listener. 124 * 125 * @param listeners The listeners to forward the calls. 126 */ 127 public MultiListener(@NonNull ArrayList<NsdManager.DiscoveryListener> listeners) { 128 mListeners = listeners; 129 } 130 131 @Override 132 public void onStartDiscoveryFailed(String serviceType, int errorCode) { 133 Log.w(LOG_TAG, "Failed to start network discovery for type " + serviceType + ": " 134 + errorCode); 135 } 136 137 @Override 138 public void onStopDiscoveryFailed(String serviceType, int errorCode) { 139 Log.w(LOG_TAG, "Failed to stop network discovery for type " + serviceType + ": " 140 + errorCode); 141 } 142 143 @Override 144 public void onDiscoveryStarted(String serviceType) { 145 // not implemented 146 } 147 148 @Override 149 public void onDiscoveryStopped(String serviceType) { 150 // not implemented 151 } 152 153 @Override 154 public void onServiceFound(NsdServiceInfo serviceInfo) { 155 synchronized (mListeners) { 156 int numListeners = mListeners.size(); 157 for (int i = 0; i < numListeners; i++) { 158 NsdManager.DiscoveryListener listener = mListeners.get(i); 159 160 listener.onServiceFound(serviceInfo); 161 } 162 } 163 } 164 165 @Override 166 public void onServiceLost(NsdServiceInfo serviceInfo) { 167 synchronized (mListeners) { 168 int numListeners = mListeners.size(); 169 for (int i = 0; i < numListeners; i++) { 170 NsdManager.DiscoveryListener listener = mListeners.get(i); 171 172 listener.onServiceLost(serviceInfo); 173 } 174 } 175 } 176 } 177} 178