13bf66744d61d18c66d46f2608de0467ad3df0268Mopria/* 23bf66744d61d18c66d46f2608de0467ad3df0268Mopria * Copyright (C) 2016 The Android Open Source Project 33bf66744d61d18c66d46f2608de0467ad3df0268Mopria * 43bf66744d61d18c66d46f2608de0467ad3df0268Mopria * Licensed under the Apache License, Version 2.0 (the "License"); 53bf66744d61d18c66d46f2608de0467ad3df0268Mopria * you may not use this file except in compliance with the License. 63bf66744d61d18c66d46f2608de0467ad3df0268Mopria * You may obtain a copy of the License at 73bf66744d61d18c66d46f2608de0467ad3df0268Mopria * 83bf66744d61d18c66d46f2608de0467ad3df0268Mopria * http://www.apache.org/licenses/LICENSE-2.0 93bf66744d61d18c66d46f2608de0467ad3df0268Mopria * 103bf66744d61d18c66d46f2608de0467ad3df0268Mopria * Unless required by applicable law or agreed to in writing, software 113bf66744d61d18c66d46f2608de0467ad3df0268Mopria * distributed under the License is distributed on an "AS IS" BASIS, 123bf66744d61d18c66d46f2608de0467ad3df0268Mopria * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133bf66744d61d18c66d46f2608de0467ad3df0268Mopria * See the License for the specific language governing permissions and 143bf66744d61d18c66d46f2608de0467ad3df0268Mopria * limitations under the License. 153bf66744d61d18c66d46f2608de0467ad3df0268Mopria */ 163bf66744d61d18c66d46f2608de0467ad3df0268Mopria 173bf66744d61d18c66d46f2608de0467ad3df0268Mopriapackage com.android.bips.discovery; 183bf66744d61d18c66d46f2608de0467ad3df0268Mopria 193bf66744d61d18c66d46f2608de0467ad3df0268Mopriaimport android.content.Context; 203bf66744d61d18c66d46f2608de0467ad3df0268Mopriaimport android.net.nsd.NsdManager; 213bf66744d61d18c66d46f2608de0467ad3df0268Mopriaimport android.net.nsd.NsdServiceInfo; 223bf66744d61d18c66d46f2608de0467ad3df0268Mopriaimport android.os.Handler; 233bf66744d61d18c66d46f2608de0467ad3df0268Mopriaimport android.util.Log; 243bf66744d61d18c66d46f2608de0467ad3df0268Mopria 253bf66744d61d18c66d46f2608de0467ad3df0268Mopriaimport java.util.LinkedList; 263bf66744d61d18c66d46f2608de0467ad3df0268Mopria 273bf66744d61d18c66d46f2608de0467ad3df0268Mopria/** 283bf66744d61d18c66d46f2608de0467ad3df0268Mopria * Nsd resolve requests for the same info cancel each other. Hence this class synchronizes the 293bf66744d61d18c66d46f2608de0467ad3df0268Mopria * resolutions to hide this effect. 303bf66744d61d18c66d46f2608de0467ad3df0268Mopria */ 313bf66744d61d18c66d46f2608de0467ad3df0268Mopriaclass NsdResolveQueue { 323bf66744d61d18c66d46f2608de0467ad3df0268Mopria private static final String TAG = NsdResolveQueue.class.getSimpleName(); 333bf66744d61d18c66d46f2608de0467ad3df0268Mopria private static final boolean DEBUG = false; 343bf66744d61d18c66d46f2608de0467ad3df0268Mopria 353bf66744d61d18c66d46f2608de0467ad3df0268Mopria /** Lock for {@link #sInstance} */ 363bf66744d61d18c66d46f2608de0467ad3df0268Mopria private static final Object sLock = new Object(); 373bf66744d61d18c66d46f2608de0467ad3df0268Mopria 383bf66744d61d18c66d46f2608de0467ad3df0268Mopria /** Instance of this singleton */ 393bf66744d61d18c66d46f2608de0467ad3df0268Mopria private static NsdResolveQueue sInstance; 403bf66744d61d18c66d46f2608de0467ad3df0268Mopria 413bf66744d61d18c66d46f2608de0467ad3df0268Mopria /** Current set of registered service info resolve attempts */ 423bf66744d61d18c66d46f2608de0467ad3df0268Mopria final LinkedList<NsdResolveRequest> mResolveRequests = new LinkedList<>(); 433bf66744d61d18c66d46f2608de0467ad3df0268Mopria 443bf66744d61d18c66d46f2608de0467ad3df0268Mopria private final Handler mMainHandler; 453bf66744d61d18c66d46f2608de0467ad3df0268Mopria 463bf66744d61d18c66d46f2608de0467ad3df0268Mopria public static NsdResolveQueue getInstance(Context context) { 473bf66744d61d18c66d46f2608de0467ad3df0268Mopria synchronized (sLock) { 483bf66744d61d18c66d46f2608de0467ad3df0268Mopria if (sInstance == null) { 493bf66744d61d18c66d46f2608de0467ad3df0268Mopria sInstance = new NsdResolveQueue(context); 503bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 513bf66744d61d18c66d46f2608de0467ad3df0268Mopria return sInstance; 523bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 533bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 543bf66744d61d18c66d46f2608de0467ad3df0268Mopria 553bf66744d61d18c66d46f2608de0467ad3df0268Mopria private NsdResolveQueue(Context context) { 563bf66744d61d18c66d46f2608de0467ad3df0268Mopria mMainHandler = new Handler(context.getMainLooper()); 573bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 583bf66744d61d18c66d46f2608de0467ad3df0268Mopria 593bf66744d61d18c66d46f2608de0467ad3df0268Mopria /** 603bf66744d61d18c66d46f2608de0467ad3df0268Mopria * Resolve a serviceInfo or queue the request if there is a request currently in flight. 613bf66744d61d18c66d46f2608de0467ad3df0268Mopria * 623bf66744d61d18c66d46f2608de0467ad3df0268Mopria * @param nsdManager The nsd manager to use 633bf66744d61d18c66d46f2608de0467ad3df0268Mopria * @param serviceInfo The service info to resolve 643bf66744d61d18c66d46f2608de0467ad3df0268Mopria * @param listener The listener to call back once the info is resolved. 653bf66744d61d18c66d46f2608de0467ad3df0268Mopria */ 663bf66744d61d18c66d46f2608de0467ad3df0268Mopria public void resolve(NsdManager nsdManager, NsdServiceInfo serviceInfo, 673bf66744d61d18c66d46f2608de0467ad3df0268Mopria NsdManager.ResolveListener listener) { 683bf66744d61d18c66d46f2608de0467ad3df0268Mopria if (DEBUG) { 693bf66744d61d18c66d46f2608de0467ad3df0268Mopria Log.d(TAG, "Adding resolve of " + serviceInfo.getServiceName() + " to queue size=" + 703bf66744d61d18c66d46f2608de0467ad3df0268Mopria mResolveRequests.size()); 713bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 723bf66744d61d18c66d46f2608de0467ad3df0268Mopria mResolveRequests.addLast(new NsdResolveRequest(nsdManager, serviceInfo, listener)); 733bf66744d61d18c66d46f2608de0467ad3df0268Mopria if (mResolveRequests.size() == 1) { 743bf66744d61d18c66d46f2608de0467ad3df0268Mopria resolveNextRequest(); 753bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 763bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 773bf66744d61d18c66d46f2608de0467ad3df0268Mopria 783bf66744d61d18c66d46f2608de0467ad3df0268Mopria /** Immediately reject all unstarted requests */ 793bf66744d61d18c66d46f2608de0467ad3df0268Mopria void clear() { 803bf66744d61d18c66d46f2608de0467ad3df0268Mopria while (mResolveRequests.size() > 1) { 813bf66744d61d18c66d46f2608de0467ad3df0268Mopria mResolveRequests.remove(1); 823bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 833bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 843bf66744d61d18c66d46f2608de0467ad3df0268Mopria 853bf66744d61d18c66d46f2608de0467ad3df0268Mopria /** 863bf66744d61d18c66d46f2608de0467ad3df0268Mopria * Resolve the next request if there is one. 873bf66744d61d18c66d46f2608de0467ad3df0268Mopria */ 883bf66744d61d18c66d46f2608de0467ad3df0268Mopria private void resolveNextRequest() { 893bf66744d61d18c66d46f2608de0467ad3df0268Mopria if (!mResolveRequests.isEmpty()) { 903bf66744d61d18c66d46f2608de0467ad3df0268Mopria mResolveRequests.getFirst().start(); 913bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 923bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 933bf66744d61d18c66d46f2608de0467ad3df0268Mopria 943bf66744d61d18c66d46f2608de0467ad3df0268Mopria /** 953bf66744d61d18c66d46f2608de0467ad3df0268Mopria * Holds a request to resolve a {@link NsdServiceInfo} 963bf66744d61d18c66d46f2608de0467ad3df0268Mopria */ 973bf66744d61d18c66d46f2608de0467ad3df0268Mopria private class NsdResolveRequest implements NsdManager.ResolveListener { 983bf66744d61d18c66d46f2608de0467ad3df0268Mopria final NsdManager nsdManager; 993bf66744d61d18c66d46f2608de0467ad3df0268Mopria final NsdServiceInfo serviceInfo; 1003bf66744d61d18c66d46f2608de0467ad3df0268Mopria final NsdManager.ResolveListener listener; 1013bf66744d61d18c66d46f2608de0467ad3df0268Mopria private long mStartTime; 1023bf66744d61d18c66d46f2608de0467ad3df0268Mopria 1033bf66744d61d18c66d46f2608de0467ad3df0268Mopria private NsdResolveRequest(NsdManager nsdManager, 1043bf66744d61d18c66d46f2608de0467ad3df0268Mopria NsdServiceInfo serviceInfo, 1053bf66744d61d18c66d46f2608de0467ad3df0268Mopria NsdManager.ResolveListener listener) { 1063bf66744d61d18c66d46f2608de0467ad3df0268Mopria this.nsdManager = nsdManager; 1073bf66744d61d18c66d46f2608de0467ad3df0268Mopria this.serviceInfo = serviceInfo; 1083bf66744d61d18c66d46f2608de0467ad3df0268Mopria this.listener = listener; 1093bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 1103bf66744d61d18c66d46f2608de0467ad3df0268Mopria 1113bf66744d61d18c66d46f2608de0467ad3df0268Mopria public void start() { 1123bf66744d61d18c66d46f2608de0467ad3df0268Mopria mStartTime = System.currentTimeMillis(); 1133bf66744d61d18c66d46f2608de0467ad3df0268Mopria if (DEBUG) Log.d(TAG, "resolveService " + serviceInfo.getServiceName()); 1143bf66744d61d18c66d46f2608de0467ad3df0268Mopria nsdManager.resolveService(serviceInfo, this); 1153bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 1163bf66744d61d18c66d46f2608de0467ad3df0268Mopria 1173bf66744d61d18c66d46f2608de0467ad3df0268Mopria @Override 1183bf66744d61d18c66d46f2608de0467ad3df0268Mopria public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { 1193bf66744d61d18c66d46f2608de0467ad3df0268Mopria if (DEBUG) { 1203bf66744d61d18c66d46f2608de0467ad3df0268Mopria Log.d(TAG, "onResolveFailed " + serviceInfo.getServiceName() + " errorCode=" + 1213bf66744d61d18c66d46f2608de0467ad3df0268Mopria errorCode + " (" + (System.currentTimeMillis() - mStartTime) + " ms)"); 1223bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 1233bf66744d61d18c66d46f2608de0467ad3df0268Mopria mMainHandler.post(() -> { 1243bf66744d61d18c66d46f2608de0467ad3df0268Mopria listener.onResolveFailed(serviceInfo, errorCode); 1253bf66744d61d18c66d46f2608de0467ad3df0268Mopria mResolveRequests.pop(); 1263bf66744d61d18c66d46f2608de0467ad3df0268Mopria resolveNextRequest(); 1273bf66744d61d18c66d46f2608de0467ad3df0268Mopria }); 1283bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 1293bf66744d61d18c66d46f2608de0467ad3df0268Mopria 1303bf66744d61d18c66d46f2608de0467ad3df0268Mopria @Override 1313bf66744d61d18c66d46f2608de0467ad3df0268Mopria public void onServiceResolved(NsdServiceInfo serviceInfo) { 1323bf66744d61d18c66d46f2608de0467ad3df0268Mopria if (DEBUG) { 1333bf66744d61d18c66d46f2608de0467ad3df0268Mopria Log.d(TAG, "onServiceResolved " + serviceInfo.getServiceName() + 1343bf66744d61d18c66d46f2608de0467ad3df0268Mopria " (" + (System.currentTimeMillis() - mStartTime) + " ms)"); 1353bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 1363bf66744d61d18c66d46f2608de0467ad3df0268Mopria mMainHandler.post(() -> { 1373bf66744d61d18c66d46f2608de0467ad3df0268Mopria listener.onServiceResolved(serviceInfo); 1383bf66744d61d18c66d46f2608de0467ad3df0268Mopria mResolveRequests.pop(); 1393bf66744d61d18c66d46f2608de0467ad3df0268Mopria resolveNextRequest(); 1403bf66744d61d18c66d46f2608de0467ad3df0268Mopria }); 1413bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 1423bf66744d61d18c66d46f2608de0467ad3df0268Mopria } 1433bf66744d61d18c66d46f2608de0467ad3df0268Mopria}