19dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann/* 29dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * Copyright (C) 2016 The Android Open Source Project 39dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * 49dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * Licensed under the Apache License, Version 2.0 (the "License"); 59dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * you may not use this file except in compliance with the License. 69dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * You may obtain a copy of the License at 79dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * 89dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * http://www.apache.org/licenses/LICENSE-2.0 99dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * 109dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * Unless required by applicable law or agreed to in writing, software 119dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * distributed under the License is distributed on an "AS IS" BASIS, 129dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * See the License for the specific language governing permissions and 149dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * limitations under the License. 159dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann */ 169dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 179dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannpackage com.android.printservice.recommendation.plugin.mdnsFilter; 189dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 199dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannimport android.annotation.NonNull; 209dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannimport android.annotation.Nullable; 219dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannimport android.annotation.StringRes; 229dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannimport android.content.Context; 239dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannimport android.net.nsd.NsdManager; 249dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannimport android.net.nsd.NsdServiceInfo; 259dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannimport android.util.Log; 269dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannimport com.android.internal.annotations.GuardedBy; 279dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannimport com.android.internal.util.Preconditions; 289dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannimport com.android.printservice.recommendation.PrintServicePlugin; 29bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannimport com.android.printservice.recommendation.util.DiscoveryListenerMultiplexer; 309dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannimport com.android.printservice.recommendation.util.NsdResolveQueue; 319dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 329dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannimport java.util.HashSet; 339dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannimport java.util.List; 349dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 359dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann/** 369dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * A plugin listening for mDNS results and only adding the ones that {@link 379dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * MDNSUtils#isVendorPrinter match} configured list 389dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann */ 399dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmannpublic class MDNSFilterPlugin implements PrintServicePlugin, NsdManager.DiscoveryListener { 409dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann private static final String LOG_TAG = "MDNSFilterPlugin"; 419dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 429dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann private static final String PRINTER_SERVICE_TYPE = "_ipp._tcp"; 439dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 449dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann /** Name of the print service this plugin is for */ 459dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann private final @StringRes int mName; 469dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 479dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann /** Package name of the print service this plugin is for */ 489dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann private final @NonNull CharSequence mPackageName; 499dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 509dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann /** mDNS names handled by the print service this plugin is for */ 519dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann private final @NonNull HashSet<String> mMDNSNames; 529dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 539dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann /** Printer identifiers of the mPrinters found. */ 549dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @GuardedBy("mLock") 559dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann private final @NonNull HashSet<String> mPrinters; 569dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 579dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann /** Context of the user of this plugin */ 589dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann private final @NonNull Context mContext; 599dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 609dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann /** 619dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * Call back to report the number of mPrinters found. 629dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * 639dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * We assume that {@link #start} and {@link #stop} are never called in parallel, hence it is 649dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * safe to not synchronize access to this field. 659dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann */ 669dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann private @Nullable PrinterDiscoveryCallback mCallback; 679dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 689dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann /** Queue used to resolve nsd infos */ 699dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann private final @NonNull NsdResolveQueue mResolveQueue; 709dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 719dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann /** 729dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * Create new stub that assumes that a print service can be used to print on all mPrinters 739dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * matching some mDNS names. 749dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * 759dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * @param context The context the plugin runs in 769dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * @param name The user friendly name of the print service 779dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * @param packageName The package name of the print service 789dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * @param mDNSNames The mDNS names of the printer. 799dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann */ 809dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public MDNSFilterPlugin(@NonNull Context context, @NonNull String name, 819dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @NonNull CharSequence packageName, @NonNull List<String> mDNSNames) { 829dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann mContext = Preconditions.checkNotNull(context, "context"); 839dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann mName = mContext.getResources().getIdentifier(Preconditions.checkStringNotEmpty(name, 84bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann "name"), null, "com.android.printservice.recommendation"); 859dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann mPackageName = Preconditions.checkStringNotEmpty(packageName); 869dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann mMDNSNames = new HashSet<>(Preconditions 879dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann .checkCollectionNotEmpty(Preconditions.checkCollectionElementsNotNull(mDNSNames, 889dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann "mDNSNames"), "mDNSNames")); 899dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 909dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann mResolveQueue = NsdResolveQueue.getInstance(); 919dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann mPrinters = new HashSet<>(); 929dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 939dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 949dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @Override 959dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public @NonNull CharSequence getPackageName() { 969dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann return mPackageName; 979dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 989dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 999dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann /** 1009dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann * @return The NDS manager 1019dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann */ 1029dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann private NsdManager getNDSManager() { 1039dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann return (NsdManager) mContext.getSystemService(Context.NSD_SERVICE); 1049dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1059dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 1069dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @Override 1079dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public void start(@NonNull PrinterDiscoveryCallback callback) throws Exception { 1089dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann mCallback = callback; 1099dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 110bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann DiscoveryListenerMultiplexer.addListener(getNDSManager(), PRINTER_SERVICE_TYPE, this); 1119dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1129dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 1139dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @Override 1149dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public @StringRes int getName() { 1159dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann return mName; 1169dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1179dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 1189dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @Override 1199dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public void stop() throws Exception { 1209dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann mCallback.onChanged(0); 1219dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann mCallback = null; 1229dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 123bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann DiscoveryListenerMultiplexer.removeListener(getNDSManager(), this); 1249dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1259dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 1269dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @Override 1279dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public void onStartDiscoveryFailed(String serviceType, int errorCode) { 1289dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann Log.w(LOG_TAG, "Failed to start network discovery for type " + serviceType + ": " 1299dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann + errorCode); 1309dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1319dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 1329dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @Override 1339dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public void onStopDiscoveryFailed(String serviceType, int errorCode) { 1349dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann Log.w(LOG_TAG, "Failed to stop network discovery for type " + serviceType + ": " 1359dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann + errorCode); 1369dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1379dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 1389dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @Override 1399dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public void onDiscoveryStarted(String serviceType) { 1409dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann // empty 1419dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1429dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 1439dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @Override 1449dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public void onDiscoveryStopped(String serviceType) { 1459dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann mPrinters.clear(); 1469dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1479dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 1489dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @Override 1499dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public void onServiceFound(NsdServiceInfo serviceInfo) { 1509dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann mResolveQueue.resolve(getNDSManager(), serviceInfo, 1519dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann new NsdManager.ResolveListener() { 1529dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @Override 1539dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { 1549dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann Log.w(LOG_TAG, "Service found: could not resolve " + serviceInfo + ": " + 1559dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann errorCode); 1569dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1579dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 1589dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @Override 1599dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public void onServiceResolved(NsdServiceInfo serviceInfo) { 1609dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann if (MDNSUtils.isVendorPrinter(serviceInfo, mMDNSNames)) { 1619dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann if (mCallback != null) { 1629dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann boolean added = mPrinters.add(serviceInfo.getHost().getHostAddress()); 1639dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 1649dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann if (added) { 1659dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann mCallback.onChanged(mPrinters.size()); 1669dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1679dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1689dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1699dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1709dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann }); 1719dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1729dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 1739dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @Override 1749dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public void onServiceLost(NsdServiceInfo serviceInfo) { 1759dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann mResolveQueue.resolve(getNDSManager(), serviceInfo, 1769dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann new NsdManager.ResolveListener() { 1779dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @Override 1789dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { 1799dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann Log.w(LOG_TAG, "Service lost: Could not resolve " + serviceInfo + ": " 1809dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann + errorCode); 1819dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1829dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 1839dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann @Override 1849dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann public void onServiceResolved(NsdServiceInfo serviceInfo) { 1859dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann if (MDNSUtils.isVendorPrinter(serviceInfo, mMDNSNames)) { 1869dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann if (mCallback != null) { 1879dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann boolean removed = mPrinters 1889dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann .remove(serviceInfo.getHost().getHostAddress()); 1899dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann 1909dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann if (removed) { 1919dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann mCallback.onChanged(mPrinters.size()); 1929dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1939dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1949dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1959dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1969dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann }); 1979dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann } 1989dcb86a48d73f399fb1b5c020005d76d350eeac2Philip P. Moltmann} 199