blob: d82b87176299d1fa8d4e2d16d97ee7e884baedcc [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.printservice.recommendation.util;
import android.annotation.NonNull;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.util.ArrayMap;
import android.util.Log;
import java.util.ArrayList;
/**
* Used to multiplex listening for NSD services. This is needed as only a limited amount of
* {@link NsdManager.DiscoveryListener listeners} are allowed.
*/
public class DiscoveryListenerMultiplexer {
private static final String LOG_TAG = "DiscoveryListenerMx";
/** List of registered {@link DiscoveryListenerSet discovery sets}. */
private static final @NonNull ArrayMap<String, DiscoveryListenerSet> sListeners =
new ArrayMap<>();
/**
* Add a new {@link NsdManager.DiscoveryListener listener} for a {@code serviceType}.
*
* @param nsdManager The {@link NsdManager NSD manager} to use
* @param serviceType The service type to listen for
* @param newListener the {@link NsdManager.DiscoveryListener listener} to add.
*/
public static void addListener(@NonNull NsdManager nsdManager, @NonNull String serviceType,
@NonNull NsdManager.DiscoveryListener newListener) {
synchronized (sListeners) {
DiscoveryListenerSet listenerSet = sListeners.get(serviceType);
if (listenerSet == null) {
ArrayList<NsdManager.DiscoveryListener> subListeners = new ArrayList<>(1);
listenerSet = new DiscoveryListenerSet(subListeners,
new MultiListener(subListeners));
sListeners.put(serviceType, listenerSet);
}
synchronized (listenerSet.subListeners) {
if (listenerSet.subListeners.isEmpty()) {
nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD,
listenerSet.mainListener);
}
listenerSet.subListeners.add(newListener);
}
}
}
/**
* Remove a previously added {@link NsdManager.DiscoveryListener listener}.
*
* @param nsdManager The {@link NsdManager NSD manager} to use
* @param listener The {@link NsdManager.DiscoveryListener listener} that was registered
*
* @return true iff the listener was removed
*/
public static boolean removeListener(@NonNull NsdManager nsdManager,
@NonNull NsdManager.DiscoveryListener listener) {
boolean wasRemoved = false;
synchronized (sListeners) {
for (DiscoveryListenerSet listeners : sListeners.values()) {
synchronized (listeners) {
wasRemoved = listeners.subListeners.remove(listener);
if (wasRemoved) {
if (listeners.subListeners.isEmpty()) {
nsdManager.stopServiceDiscovery(listeners.mainListener);
}
break;
}
}
}
}
return wasRemoved;
}
/** Private class holding all data for a service type */
private static class DiscoveryListenerSet {
/** The plugin's listeners */
final @NonNull ArrayList<NsdManager.DiscoveryListener> subListeners;
/** The listener registered with the NSD Manager */
final @NonNull MultiListener mainListener;
private DiscoveryListenerSet(ArrayList<NsdManager.DiscoveryListener> subListeners,
MultiListener mainListener) {
this.subListeners = subListeners;
this.mainListener = mainListener;
}
}
/**
* A {@link NsdManager.DiscoveryListener} that calls a list of registered listeners when
* a service is found or lost.
*/
private static class MultiListener implements NsdManager.DiscoveryListener {
private final @NonNull ArrayList<NsdManager.DiscoveryListener> mListeners;
/**
* Create a new multi listener.
*
* @param listeners The listeners to forward the calls.
*/
public MultiListener(@NonNull ArrayList<NsdManager.DiscoveryListener> listeners) {
mListeners = listeners;
}
@Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
Log.w(LOG_TAG, "Failed to start network discovery for type " + serviceType + ": "
+ errorCode);
}
@Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
Log.w(LOG_TAG, "Failed to stop network discovery for type " + serviceType + ": "
+ errorCode);
}
@Override
public void onDiscoveryStarted(String serviceType) {
// not implemented
}
@Override
public void onDiscoveryStopped(String serviceType) {
// not implemented
}
@Override
public void onServiceFound(NsdServiceInfo serviceInfo) {
synchronized (mListeners) {
int numListeners = mListeners.size();
for (int i = 0; i < numListeners; i++) {
NsdManager.DiscoveryListener listener = mListeners.get(i);
listener.onServiceFound(serviceInfo);
}
}
}
@Override
public void onServiceLost(NsdServiceInfo serviceInfo) {
synchronized (mListeners) {
int numListeners = mListeners.size();
for (int i = 0; i < numListeners; i++) {
NsdManager.DiscoveryListener listener = mListeners.get(i);
listener.onServiceLost(serviceInfo);
}
}
}
}
}