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 17 package com.android.bips.discovery; 18 19 import android.content.Context; 20 import android.net.nsd.NsdManager; 21 import android.net.nsd.NsdServiceInfo; 22 import android.os.Handler; 23 import android.util.Log; 24 25 import java.util.LinkedList; 26 27 /** 28 * Queues Nsd resolve requests to prevent multiple simultaneous requests to NsdManager 29 */ 30 public class NsdResolveQueue { 31 private static final String TAG = NsdResolveQueue.class.getSimpleName(); 32 private static final boolean DEBUG = false; 33 34 private final NsdManager mNsdManager; 35 private final Handler mMainHandler; 36 37 /** Current set of registered service info resolve attempts */ 38 private LinkedList<NsdResolveRequest> mResolveRequests = new LinkedList<>(); 39 NsdResolveQueue(Context context, NsdManager nsdManager)40 public NsdResolveQueue(Context context, NsdManager nsdManager) { 41 mNsdManager = nsdManager; 42 mMainHandler = new Handler(context.getMainLooper()); 43 } 44 45 /** Return the {@link NsdManager} used by this queue */ getNsdManager()46 NsdManager getNsdManager() { 47 return mNsdManager; 48 } 49 50 /** 51 * Resolve a serviceInfo or queue the request if there is a request currently in flight. 52 * 53 * @param serviceInfo The service info to resolve 54 * @param listener The listener to call back once the info is resolved. 55 */ resolve(NsdServiceInfo serviceInfo, NsdManager.ResolveListener listener)56 public NsdResolveRequest resolve(NsdServiceInfo serviceInfo, 57 NsdManager.ResolveListener listener) { 58 if (DEBUG) { 59 Log.d(TAG, "Adding resolve of " + serviceInfo.getServiceName() + " to queue size=" 60 + mResolveRequests.size()); 61 } 62 NsdResolveRequest request = new NsdResolveRequest(mNsdManager, serviceInfo, listener); 63 mResolveRequests.addLast(request); 64 if (mResolveRequests.size() == 1) { 65 resolveNextRequest(); 66 } 67 return request; 68 } 69 70 /** 71 * Resolve the next request if there is one. 72 */ resolveNextRequest()73 private void resolveNextRequest() { 74 if (!mResolveRequests.isEmpty()) { 75 mResolveRequests.getFirst().start(); 76 } 77 } 78 79 /** 80 * Holds a request to resolve a {@link NsdServiceInfo} 81 */ 82 class NsdResolveRequest implements NsdManager.ResolveListener { 83 private final NsdManager mNsdManager; 84 private final NsdServiceInfo mServiceInfo; 85 private final NsdManager.ResolveListener mListener; 86 private long mStartTime; 87 NsdResolveRequest(NsdManager nsdManager, NsdServiceInfo serviceInfo, NsdManager.ResolveListener listener)88 private NsdResolveRequest(NsdManager nsdManager, 89 NsdServiceInfo serviceInfo, 90 NsdManager.ResolveListener listener) { 91 mNsdManager = nsdManager; 92 mServiceInfo = serviceInfo; 93 mListener = listener; 94 } 95 start()96 private void start() { 97 mStartTime = System.currentTimeMillis(); 98 if (DEBUG) Log.d(TAG, "resolveService " + mServiceInfo.getServiceName()); 99 mNsdManager.resolveService(mServiceInfo, this); 100 } 101 cancel()102 void cancel() { 103 // Note: resolve requests can only be cancelled if they have not yet begun 104 if (!mResolveRequests.isEmpty() && mResolveRequests.get(0) != this) { 105 mResolveRequests.remove(this); 106 } 107 } 108 109 @Override onResolveFailed(NsdServiceInfo serviceInfo, int errorCode)110 public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { 111 if (DEBUG) { 112 Log.d(TAG, "onResolveFailed " + serviceInfo.getServiceName() + " errorCode=" 113 + errorCode + " (" + (System.currentTimeMillis() - mStartTime) + " ms)"); 114 } 115 mMainHandler.post(() -> { 116 mListener.onResolveFailed(serviceInfo, errorCode); 117 mResolveRequests.pop(); 118 resolveNextRequest(); 119 }); 120 } 121 122 @Override onServiceResolved(NsdServiceInfo serviceInfo)123 public void onServiceResolved(NsdServiceInfo serviceInfo) { 124 if (DEBUG) { 125 Log.d(TAG, "onServiceResolved " + serviceInfo.getServiceName() 126 + " (" + (System.currentTimeMillis() - mStartTime) + " ms)"); 127 } 128 mMainHandler.post(() -> { 129 mListener.onServiceResolved(serviceInfo); 130 mResolveRequests.pop(); 131 resolveNextRequest(); 132 }); 133 } 134 } 135 } 136