summaryrefslogtreecommitdiff
path: root/packages/PrintRecommendationService/src
diff options
context:
space:
mode:
authorSergey Yakovlev <s.yakovlev@samsung.com>2016-11-18 18:59:47 +0300
committerSergey Yakovlev <s.yakovlev@samsung.com>2016-11-23 13:26:48 +0300
commit989c44be2c383568fcd4e4373ed5acb5442a019e (patch)
tree4d37d962b2930b3c138a397286f9e16f826f864f /packages/PrintRecommendationService/src
parentebb722d04af4aa8626e32e0e8a9b885b11d03c0f (diff)
Update Samsung Print Recommendation Plugin (to support Mopria printers)
- Extract common part of MDNSFilterPlugin to common utils, MDNSFilteredDiscovery.java (other vendors can use it too) - Refactor Samsung Print Recomendation Plugin to use MDNSFilteredDiscovery.java - Add Mopria devices detection to Samsung Print Recomendation Plugin *Samsung Print Service Plugin supports Mopria printers since v3.00.161011. Test: Tested manually. Test app was developed to make sure that Samsung Print Recommendation plugin can find both Samsung and Mopria devices. Additionally MDNSFilterPlugin was tested on HP printers. Change-Id: Idc0d311171495f879564336370a86f7a8890378b
Diffstat (limited to 'packages/PrintRecommendationService/src')
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java2
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java172
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/MDnsUtils.java74
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterMopria.java63
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterSamsung.java117
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterHashMap.java33
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/SamsungRecommendationPlugin.java171
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceListener.java186
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceRecommendationPlugin.java86
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceResolveQueue.java109
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/VendorInfo.java40
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java212
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java (renamed from packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSUtils.java)38
13 files changed, 541 insertions, 762 deletions
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
index ac60a88e5ca6..1fe5a2a4d40b 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
@@ -78,7 +78,7 @@ public class RecommendationServiceImpl extends RecommendationService
try {
mPlugins.add(new RemotePrintServicePlugin(new SamsungRecommendationPlugin(this), this,
- false));
+ true));
} catch (Exception e) {
Log.e(LOG_TAG, "Could not initiate " + getString(R.string.plugin_vendor_samsung) +
" plugin", e);
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
index a2c0485f3d0a..d60a25f54a22 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
@@ -16,30 +16,52 @@
package com.android.printservice.recommendation.plugin.mdnsFilter;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringRes;
import android.content.Context;
-import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
-import android.util.Log;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
+import android.annotation.NonNull;
+import android.annotation.StringRes;
+
import com.android.printservice.recommendation.PrintServicePlugin;
-import com.android.printservice.recommendation.util.DiscoveryListenerMultiplexer;
-import com.android.printservice.recommendation.util.NsdResolveQueue;
+import com.android.printservice.recommendation.util.MDNSFilteredDiscovery;
+import com.android.printservice.recommendation.util.MDNSUtils;
import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* A plugin listening for mDNS results and only adding the ones that {@link
* MDNSUtils#isVendorPrinter match} configured list
*/
-public class MDNSFilterPlugin implements PrintServicePlugin, NsdManager.DiscoveryListener {
- private static final String LOG_TAG = "MDNSFilterPlugin";
+public class MDNSFilterPlugin implements PrintServicePlugin {
- private static final String PRINTER_SERVICE_TYPE = "_ipp._tcp";
+ /** The mDNS service types supported */
+ private static final Set<String> PRINTER_SERVICE_TYPES = new HashSet<String>() {{
+ add("_ipp._tcp");
+ }};
+
+ /**
+ * The printer filter for {@link MDNSFilteredDiscovery} passing only mDNS results
+ * that {@link MDNSUtils#isVendorPrinter match} configured list
+ */
+ private static class VendorNameFilter implements MDNSFilteredDiscovery.PrinterFilter {
+ /** mDNS names handled by the print service this plugin is for */
+ private final @NonNull Set<String> mMDNSNames;
+
+ /**
+ * Filter constructor
+ *
+ * @param vendorNames The vendor names to pass
+ */
+ VendorNameFilter(@NonNull Set<String> vendorNames) {
+ mMDNSNames = new HashSet<>(vendorNames);
+ }
+
+ @Override
+ public boolean matchesCriteria(NsdServiceInfo nsdServiceInfo) {
+ return MDNSUtils.isVendorPrinter(nsdServiceInfo, mMDNSNames);
+ }
+ }
/** Name of the print service this plugin is for */
private final @StringRes int mName;
@@ -47,26 +69,8 @@ public class MDNSFilterPlugin implements PrintServicePlugin, NsdManager.Discover
/** Package name of the print service this plugin is for */
private final @NonNull CharSequence mPackageName;
- /** mDNS names handled by the print service this plugin is for */
- private final @NonNull HashSet<String> mMDNSNames;
-
- /** Printer identifiers of the mPrinters found. */
- @GuardedBy("mLock")
- private final @NonNull HashSet<String> mPrinters;
-
- /** Context of the user of this plugin */
- private final @NonNull Context mContext;
-
- /**
- * Call back to report the number of mPrinters found.
- *
- * We assume that {@link #start} and {@link #stop} are never called in parallel, hence it is
- * safe to not synchronize access to this field.
- */
- private @Nullable PrinterDiscoveryCallback mCallback;
-
- /** Queue used to resolve nsd infos */
- private final @NonNull NsdResolveQueue mResolveQueue;
+ /** The mDNS filtered discovery */
+ private final MDNSFilteredDiscovery mMDNSFilteredDiscovery;
/**
* Create new stub that assumes that a print service can be used to print on all mPrinters
@@ -79,16 +83,11 @@ public class MDNSFilterPlugin implements PrintServicePlugin, NsdManager.Discover
*/
public MDNSFilterPlugin(@NonNull Context context, @NonNull String name,
@NonNull CharSequence packageName, @NonNull List<String> mDNSNames) {
- mContext = Preconditions.checkNotNull(context, "context");
- mName = mContext.getResources().getIdentifier(Preconditions.checkStringNotEmpty(name,
- "name"), null, "com.android.printservice.recommendation");
- mPackageName = Preconditions.checkStringNotEmpty(packageName);
- mMDNSNames = new HashSet<>(Preconditions
- .checkCollectionNotEmpty(Preconditions.checkCollectionElementsNotNull(mDNSNames,
- "mDNSNames"), "mDNSNames"));
-
- mResolveQueue = NsdResolveQueue.getInstance();
- mPrinters = new HashSet<>();
+ mName = context.getResources().getIdentifier(name, null,
+ "com.android.printservice.recommendation");
+ mPackageName = packageName;
+ mMDNSFilteredDiscovery = new MDNSFilteredDiscovery(context, PRINTER_SERVICE_TYPES,
+ new VendorNameFilter(new HashSet<>(mDNSNames)));
}
@Override
@@ -96,18 +95,9 @@ public class MDNSFilterPlugin implements PrintServicePlugin, NsdManager.Discover
return mPackageName;
}
- /**
- * @return The NDS manager
- */
- private NsdManager getNDSManager() {
- return (NsdManager) mContext.getSystemService(Context.NSD_SERVICE);
- }
-
@Override
public void start(@NonNull PrinterDiscoveryCallback callback) throws Exception {
- mCallback = callback;
-
- DiscoveryListenerMultiplexer.addListener(getNDSManager(), PRINTER_SERVICE_TYPE, this);
+ mMDNSFilteredDiscovery.start(callback);
}
@Override
@@ -117,82 +107,6 @@ public class MDNSFilterPlugin implements PrintServicePlugin, NsdManager.Discover
@Override
public void stop() throws Exception {
- mCallback.onChanged(0);
- mCallback = null;
-
- DiscoveryListenerMultiplexer.removeListener(getNDSManager(), this);
- }
-
- @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) {
- // empty
- }
-
- @Override
- public void onDiscoveryStopped(String serviceType) {
- mPrinters.clear();
- }
-
- @Override
- public void onServiceFound(NsdServiceInfo serviceInfo) {
- mResolveQueue.resolve(getNDSManager(), serviceInfo,
- new NsdManager.ResolveListener() {
- @Override
- public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
- Log.w(LOG_TAG, "Service found: could not resolve " + serviceInfo + ": " +
- errorCode);
- }
-
- @Override
- public void onServiceResolved(NsdServiceInfo serviceInfo) {
- if (MDNSUtils.isVendorPrinter(serviceInfo, mMDNSNames)) {
- if (mCallback != null) {
- boolean added = mPrinters.add(serviceInfo.getHost().getHostAddress());
-
- if (added) {
- mCallback.onChanged(mPrinters.size());
- }
- }
- }
- }
- });
- }
-
- @Override
- public void onServiceLost(NsdServiceInfo serviceInfo) {
- mResolveQueue.resolve(getNDSManager(), serviceInfo,
- new NsdManager.ResolveListener() {
- @Override
- public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
- Log.w(LOG_TAG, "Service lost: Could not resolve " + serviceInfo + ": "
- + errorCode);
- }
-
- @Override
- public void onServiceResolved(NsdServiceInfo serviceInfo) {
- if (MDNSUtils.isVendorPrinter(serviceInfo, mMDNSNames)) {
- if (mCallback != null) {
- boolean removed = mPrinters
- .remove(serviceInfo.getHost().getHostAddress());
-
- if (removed) {
- mCallback.onChanged(mPrinters.size());
- }
- }
- }
- }
- });
+ mMDNSFilteredDiscovery.stop();
}
}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/MDnsUtils.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/MDnsUtils.java
deleted file mode 100644
index 963e09b25257..000000000000
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/MDnsUtils.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.plugin.samsung;
-
-import android.net.nsd.NsdServiceInfo;
-import android.text.TextUtils;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Locale;
-import java.util.Map;
-
-public class MDnsUtils {
- public static final String ATTRIBUTE__TY = "ty";
- public static final String ATTRIBUTE__PRODUCT = "product";
- public static final String ATTRIBUTE__USB_MFG = "usb_MFG";
- public static final String ATTRIBUTE__MFG = "mfg";
-
- public static String getString(byte[] value) {
- if (value != null) return new String(value,StandardCharsets.UTF_8);
- return null;
- }
-
- public static boolean isVendorPrinter(NsdServiceInfo networkDevice, String[] vendorValues) {
-
- Map<String,byte[]> attributes = networkDevice.getAttributes();
- String product = getString(attributes.get(ATTRIBUTE__PRODUCT));
- String ty = getString(attributes.get(ATTRIBUTE__TY));
- String usbMfg = getString(attributes.get(ATTRIBUTE__USB_MFG));
- String mfg = getString(attributes.get(ATTRIBUTE__MFG));
- return containsVendor(product, vendorValues) || containsVendor(ty, vendorValues) || containsVendor(usbMfg, vendorValues) || containsVendor(mfg, vendorValues);
-
- }
-
- public static String getVendor(NsdServiceInfo networkDevice) {
- String vendor;
-
- Map<String,byte[]> attributes = networkDevice.getAttributes();
- vendor = getString(attributes.get(ATTRIBUTE__MFG));
- if (!TextUtils.isEmpty(vendor)) return vendor;
- vendor = getString(attributes.get(ATTRIBUTE__USB_MFG));
- if (!TextUtils.isEmpty(vendor)) return vendor;
-
- return null;
- }
-
- private static boolean containsVendor(String container, String[] vendorValues) {
- if ((container == null) || (vendorValues == null)) return false;
- for (String value : vendorValues) {
- if (containsString(container, value)
- || containsString(container.toLowerCase(Locale.US), value.toLowerCase(Locale.US))
- || containsString(container.toUpperCase(Locale.US), value.toUpperCase(Locale.US)))
- return true;
- }
- return false;
- }
-
- private static boolean containsString(String container, String contained) {
- return (container != null) && (contained != null) && (container.equalsIgnoreCase(contained) || container.contains(contained + " "));
- }
-}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterMopria.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterMopria.java
new file mode 100644
index 000000000000..d03bb1d76003
--- /dev/null
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterMopria.java
@@ -0,0 +1,63 @@
+/*
+ * (c) Copyright 2016 Samsung Electronics
+ * (c) Copyright 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.plugin.samsung;
+
+import android.net.nsd.NsdServiceInfo;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.printservice.recommendation.util.MDNSFilteredDiscovery;
+import com.android.printservice.recommendation.util.MDNSUtils;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Printer filter for Mopria printer models supported by the print service plugin
+ */
+class PrinterFilterMopria implements MDNSFilteredDiscovery.PrinterFilter {
+ private static final String TAG = "PrinterFilterMopria";
+
+ static final Set<String> MOPRIA_MDNS_SERVICES = new HashSet<String>() {{
+ add("_ipp._tcp");
+ add("_ipps._tcp");
+ }};
+
+ private static final String PDL__PDF = "application/pdf";
+ private static final String PDL__PCLM = "application/PCLm";
+ private static final String PDL__PWG_RASTER = "image/pwg-raster";
+
+ private static final String PDL_ATTRIBUTE = "pdl";
+
+ @Override
+ public boolean matchesCriteria(NsdServiceInfo nsdServiceInfo) {
+ if (!MDNSUtils.isSupportedServiceType(nsdServiceInfo, MOPRIA_MDNS_SERVICES)) {
+ return false;
+ }
+
+ String pdls = MDNSUtils.getString(nsdServiceInfo.getAttributes().get(PDL_ATTRIBUTE));
+ boolean isMatch = !TextUtils.isEmpty(pdls)
+ && (pdls.contains(PDL__PDF)
+ || pdls.contains(PDL__PCLM)
+ || pdls.contains(PDL__PWG_RASTER));
+
+ if (isMatch) {
+ Log.d(TAG, "Mopria printer found: " + nsdServiceInfo.getServiceName());
+ }
+ return isMatch;
+ }
+}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterSamsung.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterSamsung.java
new file mode 100644
index 000000000000..5b049efcf514
--- /dev/null
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterSamsung.java
@@ -0,0 +1,117 @@
+/*
+ * (c) Copyright 2016 Samsung Electronics
+ * (c) Copyright 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.plugin.samsung;
+
+import android.net.nsd.NsdServiceInfo;
+import android.annotation.NonNull;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.printservice.recommendation.util.MDNSFilteredDiscovery;
+import com.android.printservice.recommendation.util.MDNSUtils;
+
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Printer filter for Samsung printer models supported by the print service plugin
+ */
+class PrinterFilterSamsung implements MDNSFilteredDiscovery.PrinterFilter {
+ private static final String TAG = "PrinterFilterSamsung";
+
+ static final Set<String> SAMSUNG_MDNS_SERVICES = new HashSet<String>() {{
+ add("_pdl-datastream._tcp");
+ }};
+
+ private static final String[] NOT_SUPPORTED_MODELS = new String[]{
+ "SCX-5x15",
+ "SF-555P",
+ "CF-555P",
+ "SCX-4x16",
+ "SCX-4214F",
+ "CLP-500",
+ "CJX-",
+ "MJC-"
+ };
+ private static final String ATTR_USB_MFG = "usb_MFG";
+ private static final String ATTR_MFG = "mfg";
+ private static final String ATTR_USB_MDL = "usb_MDL";
+ private static final String ATTR_MDL = "mdl";
+ private static final String ATTR_PRODUCT = "product";
+ private static final String ATTR_TY = "ty";
+
+ private static Set<String> SAMUNG_VENDOR_SET = new HashSet<String>() {{
+ add("samsung");
+ }};
+
+ @Override
+ public boolean matchesCriteria(NsdServiceInfo nsdServiceInfo) {
+ if (!MDNSUtils.isSupportedServiceType(nsdServiceInfo, SAMSUNG_MDNS_SERVICES)) {
+ return false;
+ }
+
+ if (!MDNSUtils.isVendorPrinter(nsdServiceInfo, SAMUNG_VENDOR_SET)) {
+ return false;
+ }
+
+ String modelName = getSamsungModelName(nsdServiceInfo);
+ if (modelName != null && isSupportedSamsungModel(modelName)) {
+ Log.d(TAG, "Samsung printer found: " + nsdServiceInfo.getServiceName());
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isSupportedSamsungModel(String model) {
+ if (!TextUtils.isEmpty(model)) {
+ String modelToUpper = model.toUpperCase(Locale.US);
+ for (String unSupportedPrinter : NOT_SUPPORTED_MODELS) {
+ if (modelToUpper.contains(unSupportedPrinter)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private String getSamsungModelName(@NonNull NsdServiceInfo resolvedDevice) {
+ Map<String,byte[]> attributes = resolvedDevice.getAttributes();
+ String usb_mfg = MDNSUtils.getString(attributes.get(ATTR_USB_MFG));
+ if (TextUtils.isEmpty(usb_mfg)) {
+ usb_mfg = MDNSUtils.getString(attributes.get(ATTR_MFG));
+ }
+
+ String usb_mdl = MDNSUtils.getString(attributes.get(ATTR_USB_MDL));
+ if (TextUtils.isEmpty(usb_mdl)) {
+ usb_mdl = MDNSUtils.getString(attributes.get(ATTR_MDL));
+ }
+
+ String modelName;
+ if (!TextUtils.isEmpty(usb_mfg) && !TextUtils.isEmpty(usb_mdl)) {
+ modelName = usb_mfg.trim() + " " + usb_mdl.trim();
+ } else {
+ modelName = MDNSUtils.getString(attributes.get(ATTR_PRODUCT));
+ if (TextUtils.isEmpty(modelName)) {
+ modelName = MDNSUtils.getString(attributes.get(ATTR_TY));
+ }
+ }
+
+ return modelName;
+ }
+}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterHashMap.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterHashMap.java
deleted file mode 100644
index 032fe22dd744..000000000000
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterHashMap.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.plugin.samsung;
-
-import android.net.nsd.NsdServiceInfo;
-
-import java.util.HashMap;
-
-final class PrinterHashMap extends HashMap<String, NsdServiceInfo> {
- public static String getKey(NsdServiceInfo serviceInfo) {
- return serviceInfo.getServiceName();
- }
- public NsdServiceInfo addPrinter(NsdServiceInfo device) {
- return put(getKey(device), device);
- }
- public NsdServiceInfo removePrinter(NsdServiceInfo device) {
- return remove(getKey(device));
- }
-}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/SamsungRecommendationPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/SamsungRecommendationPlugin.java
index e5b8a0f15f2e..eeb51229e7de 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/SamsungRecommendationPlugin.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/SamsungRecommendationPlugin.java
@@ -1,102 +1,69 @@
-/*
-(c) Copyright 2016 Samsung Electronics..
-
-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.plugin.samsung;
-
-import android.content.Context;
-import android.net.nsd.NsdServiceInfo;
-import android.text.TextUtils;
-
-import java.util.Locale;
-import java.util.Map;
-
-import com.android.printservice.recommendation.R;
-
-public class SamsungRecommendationPlugin extends ServiceRecommendationPlugin {
-
- private static final String TAG = "SamsungRecommendation";
-
- private static final String ATTR_USB_MFG = "usb_MFG";
- private static final String ATTR_MFG = "mfg";
- private static final String ATTR_USB_MDL = "usb_MDL";
- private static final String ATTR_MDL = "mdl";
- private static final String ATTR_PRODUCT = "product";
- private static final String ATTR_TY = "ty";
-
- private static String[] mNotSupportedDevices = new String[]{
- "SCX-5x15",
- "SF-555P",
- "CF-555P",
- "SCX-4x16",
- "SCX-4214F",
- "CLP-500",
- "CJX-",
- "MJC-"
- };
-
- private static boolean isSupportedModel(String model) {
- if (!TextUtils.isEmpty(model)) {
- String modelToUpper = model.toUpperCase(Locale.US);
- for (String unSupportedPrinter : mNotSupportedDevices) {
- if (modelToUpper.contains(unSupportedPrinter)) {
- return false;
- }
- }
- }
- return true;
- }
-
- public SamsungRecommendationPlugin(Context context) {
- super(context, R.string.plugin_vendor_samsung, new VendorInfo(context.getResources(), R.array.known_print_vendor_info_for_samsung), new String[]{"_pdl-datastream._tcp"});
- }
-
- @Override
- public boolean matchesCriteria(String vendor, NsdServiceInfo nsdServiceInfo) {
- if (!TextUtils.equals(vendor, mVendorInfo.mVendorID)) return false;
-
- String modelName = getModelName(nsdServiceInfo);
- if (modelName != null) {
- return (isSupportedModel(modelName));
- }
- return false;
- }
-
- private String getModelName(NsdServiceInfo resolvedDevice) {
- Map<String,byte[]> attributes = resolvedDevice.getAttributes();
- String usb_mfg = MDnsUtils.getString(attributes.get(ATTR_USB_MFG));
- if (TextUtils.isEmpty(usb_mfg)) {
- usb_mfg = MDnsUtils.getString(attributes.get(ATTR_MFG));
- }
-
- String usb_mdl = MDnsUtils.getString(attributes.get(ATTR_USB_MDL));
- if (TextUtils.isEmpty(usb_mdl)) {
- usb_mdl = MDnsUtils.getString(attributes.get(ATTR_MDL));
- }
-
- String modelName = null;
- if (!TextUtils.isEmpty(usb_mfg) && !TextUtils.isEmpty(usb_mdl)) {
- modelName = usb_mfg.trim() + " " + usb_mdl.trim();
- } else {
- modelName = MDnsUtils.getString(attributes.get(ATTR_PRODUCT));
- if (TextUtils.isEmpty(modelName)) {
- modelName = MDnsUtils.getString(attributes.get(ATTR_TY));
- }
- }
-
- return modelName;
- }
-}
+/*
+ * (c) Copyright 2016 Samsung Electronics
+ * (c) Copyright 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.plugin.samsung;
+
+import android.content.Context;
+import android.net.nsd.NsdServiceInfo;
+import android.annotation.NonNull;
+
+import com.android.printservice.recommendation.PrintServicePlugin;
+import com.android.printservice.recommendation.R;
+import com.android.printservice.recommendation.util.MDNSFilteredDiscovery;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class SamsungRecommendationPlugin implements PrintServicePlugin {
+ private static final Set<String> ALL_MDNS_SERVICES = new HashSet<String>() {{
+ addAll(PrinterFilterMopria.MOPRIA_MDNS_SERVICES);
+ addAll(PrinterFilterSamsung.SAMSUNG_MDNS_SERVICES);
+ }};
+
+ private final @NonNull Context mContext;
+ private final @NonNull MDNSFilteredDiscovery mMDNSFilteredDiscovery;
+
+ private final @NonNull PrinterFilterSamsung mPrinterFilterSamsung = new PrinterFilterSamsung();
+ private final @NonNull PrinterFilterMopria mPrinterFilterMopria = new PrinterFilterMopria();
+
+ public SamsungRecommendationPlugin(@NonNull Context context) {
+ mContext = context;
+ mMDNSFilteredDiscovery = new MDNSFilteredDiscovery(context, ALL_MDNS_SERVICES,
+ (NsdServiceInfo nsdServiceInfo) ->
+ mPrinterFilterSamsung.matchesCriteria(nsdServiceInfo) ||
+ mPrinterFilterMopria.matchesCriteria(nsdServiceInfo));
+ }
+
+ @Override
+ public int getName() {
+ return R.string.plugin_vendor_samsung;
+ }
+
+ @Override
+ public @NonNull CharSequence getPackageName() {
+ return mContext.getString(R.string.plugin_package_samsung);
+ }
+
+ @Override
+ public void start(@NonNull PrinterDiscoveryCallback callback) throws Exception {
+ mMDNSFilteredDiscovery.start(callback);
+ }
+
+ @Override
+ public void stop() throws Exception {
+ mMDNSFilteredDiscovery.stop();
+ }
+}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceListener.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceListener.java
deleted file mode 100644
index 7bb83c9384f7..000000000000
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceListener.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * 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.plugin.samsung;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.net.nsd.NsdManager;
-import android.net.nsd.NsdServiceInfo;
-import android.text.TextUtils;
-import android.util.Pair;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import com.android.printservice.recommendation.R;
-import com.android.printservice.recommendation.util.DiscoveryListenerMultiplexer;
-
-public class ServiceListener implements ServiceResolveQueue.ResolveCallback {
-
- private final NsdManager mNSDManager;
- private final Map<String, VendorInfo> mVendorInfoHashMap;
- private final String[] mServiceType;
- private final Observer mObserver;
- private final ServiceResolveQueue mResolveQueue;
- private List<NsdManager.DiscoveryListener> mListeners = new ArrayList<>();
- public HashMap<String, PrinterHashMap> mVendorHashMap = new HashMap<>();
-
- public interface Observer {
- boolean matchesCriteria(String vendor, NsdServiceInfo serviceInfo);
- void dataSetChanged();
- }
-
- public ServiceListener(Context context, Observer observer, String[] serviceTypes) {
- mObserver = observer;
- mServiceType = serviceTypes;
- mNSDManager = (NsdManager)context.getSystemService(Context.NSD_SERVICE);
- mResolveQueue = ServiceResolveQueue.getInstance(mNSDManager);
-
- Map<String, VendorInfo> vendorInfoMap = new HashMap<>();
- TypedArray testArray = context.getResources().obtainTypedArray(R.array.known_print_plugin_vendors);
- for(int i = 0; i < testArray.length(); i++) {
- int arrayID = testArray.getResourceId(i, 0);
- if (arrayID != 0) {
- VendorInfo info = new VendorInfo(context.getResources(), arrayID);
- vendorInfoMap.put(info.mVendorID, info);
- vendorInfoMap.put(info.mPackageName, info);
- }
- }
- testArray.recycle();
- mVendorInfoHashMap = vendorInfoMap;
- }
-
- @Override
- public void serviceResolved(NsdServiceInfo nsdServiceInfo) {
- printerFound(nsdServiceInfo);
- }
-
- private synchronized void printerFound(NsdServiceInfo nsdServiceInfo) {
- if (nsdServiceInfo == null) return;
- if (TextUtils.isEmpty(PrinterHashMap.getKey(nsdServiceInfo))) return;
- String vendor = MDnsUtils.getVendor(nsdServiceInfo);
- if (vendor == null) vendor = "";
- for(Map.Entry<String,VendorInfo> entry : mVendorInfoHashMap.entrySet()) {
- for(String vendorValues : entry.getValue().mDNSValues) {
- if (vendor.equalsIgnoreCase(vendorValues)) {
- vendor = entry.getValue().mVendorID;
- break;
- }
- }
- // intentional pointer check
- //noinspection StringEquality
- if ((vendor != entry.getValue().mVendorID) &&
- MDnsUtils.isVendorPrinter(nsdServiceInfo, entry.getValue().mDNSValues)) {
- vendor = entry.getValue().mVendorID;
- }
- // intentional pointer check
- //noinspection StringEquality
- if (vendor == entry.getValue().mVendorID) break;
- }
-
- if (TextUtils.isEmpty(vendor)) {
- return;
- }
-
- if (!mObserver.matchesCriteria(vendor, nsdServiceInfo))
- return;
- boolean mapsChanged;
-
- PrinterHashMap vendorHash = mVendorHashMap.get(vendor);
- if (vendorHash == null) {
- vendorHash = new PrinterHashMap();
- }
- mapsChanged = (vendorHash.addPrinter(nsdServiceInfo) == null);
- mVendorHashMap.put(vendor, vendorHash);
-
- if (mapsChanged) {
- mObserver.dataSetChanged();
- }
- }
-
- private synchronized void printerRemoved(NsdServiceInfo nsdServiceInfo) {
- boolean wasRemoved = false;
- Set<String> vendors = mVendorHashMap.keySet();
- for(String vendor : vendors) {
- PrinterHashMap map = mVendorHashMap.get(vendor);
- wasRemoved |= (map.removePrinter(nsdServiceInfo) != null);
- if (map.isEmpty()) wasRemoved |= (mVendorHashMap.remove(vendor) != null);
- }
- if (wasRemoved) {
- mObserver.dataSetChanged();
- }
- }
-
- public void start() {
- stop();
- for(final String service :mServiceType) {
- NsdManager.DiscoveryListener listener = new NsdManager.DiscoveryListener() {
- @Override
- public void onStartDiscoveryFailed(String s, int i) {
-
- }
-
- @Override
- public void onStopDiscoveryFailed(String s, int i) {
-
- }
-
- @Override
- public void onDiscoveryStarted(String s) {
-
- }
-
- @Override
- public void onDiscoveryStopped(String s) {
-
- }
-
- @Override
- public void onServiceFound(NsdServiceInfo nsdServiceInfo) {
- mResolveQueue.queueRequest(nsdServiceInfo, ServiceListener.this);
- }
-
- @Override
- public void onServiceLost(NsdServiceInfo nsdServiceInfo) {
- mResolveQueue.removeRequest(nsdServiceInfo, ServiceListener.this);
- printerRemoved(nsdServiceInfo);
- }
- };
- DiscoveryListenerMultiplexer.addListener(mNSDManager, service, listener);
- mListeners.add(listener);
- }
- }
-
- public void stop() {
- for(NsdManager.DiscoveryListener listener : mListeners) {
- DiscoveryListenerMultiplexer.removeListener(mNSDManager, listener);
- }
- mVendorHashMap.clear();
- mListeners.clear();
- }
-
- public Pair<Integer, Integer> getCount() {
- int count = 0;
- for (PrinterHashMap map : mVendorHashMap.values()) {
- count += map.size();
- }
- return Pair.create(mVendorHashMap.size(), count);
- }
-}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceRecommendationPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceRecommendationPlugin.java
deleted file mode 100644
index 9d15f3054ee2..000000000000
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceRecommendationPlugin.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.plugin.samsung;
-
-import android.content.Context;
-import android.net.nsd.NsdManager;
-import android.net.nsd.NsdServiceInfo;
-import android.annotation.NonNull;
-import android.text.TextUtils;
-import com.android.printservice.recommendation.PrintServicePlugin;
-
-public abstract class ServiceRecommendationPlugin implements PrintServicePlugin, ServiceListener.Observer {
-
- protected static final String PDL_ATTRIBUTE = "pdl";
-
- protected final Object mLock = new Object();
- protected PrinterDiscoveryCallback mCallback = null;
- protected final ServiceListener mListener;
- protected final NsdManager mNSDManager;
- protected final VendorInfo mVendorInfo;
- private final int mVendorStringID;
-
- protected ServiceRecommendationPlugin(Context context, int vendorStringID, VendorInfo vendorInfo, String[] services) {
- mNSDManager = (NsdManager)context.getSystemService(Context.NSD_SERVICE);
- mVendorStringID = vendorStringID;
- mVendorInfo = vendorInfo;
- mListener = new ServiceListener(context, this, services);
- }
-
- @Override
- public int getName() {
- return mVendorStringID;
- }
-
- @NonNull
- @Override
- public CharSequence getPackageName() {
- return mVendorInfo.mPackageName;
- }
-
- @Override
- public void start(@NonNull PrinterDiscoveryCallback callback) throws Exception {
- synchronized (mLock) {
- mCallback = callback;
- }
- mListener.start();
- }
-
- @Override
- public void stop() throws Exception {
- synchronized (mLock) {
- mCallback = null;
- }
- mListener.stop();
- }
-
- @Override
- public void dataSetChanged() {
- synchronized (mLock) {
- if (mCallback != null) mCallback.onChanged(getCount());
- }
- }
-
- @Override
- public boolean matchesCriteria(String vendor, NsdServiceInfo nsdServiceInfo) {
- return TextUtils.equals(vendor, mVendorInfo.mVendorID);
- }
-
- public int getCount() {
- return mListener.getCount().second;
- }
-}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceResolveQueue.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceResolveQueue.java
deleted file mode 100644
index e5691b734416..000000000000
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/ServiceResolveQueue.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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.plugin.samsung;
-
-import android.net.nsd.NsdManager;
-import android.net.nsd.NsdServiceInfo;
-import android.util.Pair;
-import com.android.printservice.recommendation.util.NsdResolveQueue;
-
-import java.util.LinkedList;
-
-final class ServiceResolveQueue {
-
- private final NsdManager mNsdManager;
- private final LinkedList<Pair<NsdServiceInfo, ResolveCallback>> mQueue = new LinkedList<>();
- private final Object mLock = new Object();
-
- private static Object sLock = new Object();
- private static ServiceResolveQueue sInstance = null;
- private final NsdResolveQueue mNsdResolveQueue;
- private Pair<NsdServiceInfo, ResolveCallback> mCurrentRequest = null;
-
- public static void createInstance(NsdManager nsdManager) {
- if (sInstance == null) sInstance = new ServiceResolveQueue(nsdManager);
- }
-
- public static ServiceResolveQueue getInstance(NsdManager nsdManager) {
- synchronized (sLock) {
- createInstance(nsdManager);
- return sInstance;
- }
- }
-
- public static void destroyInstance() {
- sInstance = null;
- }
-
- public interface ResolveCallback {
- void serviceResolved(NsdServiceInfo nsdServiceInfo);
- }
-
- public ServiceResolveQueue(NsdManager nsdManager) {
- mNsdManager = nsdManager;
- mNsdResolveQueue = NsdResolveQueue.getInstance();
- }
-
- public void queueRequest(NsdServiceInfo serviceInfo, ResolveCallback callback) {
- synchronized (mLock) {
- Pair<NsdServiceInfo, ResolveCallback> newRequest = Pair.create(serviceInfo, callback);
- if (mQueue.contains(newRequest)) return;
- mQueue.add(newRequest);
- makeNextRequest();
- }
- }
-
- public void removeRequest(NsdServiceInfo serviceInfo, ResolveCallback callback) {
- synchronized (mLock) {
- Pair<NsdServiceInfo, ResolveCallback> newRequest = Pair.create(serviceInfo, callback);
- mQueue.remove(newRequest);
- if ((mCurrentRequest != null) && newRequest.equals(mCurrentRequest)) mCurrentRequest = null;
- }
- }
-
- private void makeNextRequest() {
- synchronized (mLock) {
- if (mCurrentRequest != null) return;
- if (mQueue.isEmpty()) return;
- mCurrentRequest = mQueue.removeFirst();
- mNsdResolveQueue.resolve(mNsdManager, mCurrentRequest.first,
- new NsdManager.ResolveListener() {
- @Override
- public void onResolveFailed(NsdServiceInfo nsdServiceInfo, int i) {
- synchronized (mLock) {
- if (mCurrentRequest != null) mQueue.add(mCurrentRequest);
- makeNextRequest();
- }
- }
-
- @Override
- public void onServiceResolved(NsdServiceInfo nsdServiceInfo) {
- synchronized (mLock) {
- if (mCurrentRequest != null) {
- mCurrentRequest.second.serviceResolved(nsdServiceInfo);
- mCurrentRequest = null;
- }
- makeNextRequest();
- }
- }
- });
-
- }
- }
-
-
-}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/VendorInfo.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/VendorInfo.java
deleted file mode 100644
index 0ebb4e441f11..000000000000
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/VendorInfo.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.plugin.samsung;
-
-import android.content.res.Resources;
-
-import java.util.Arrays;
-
-public final class VendorInfo {
-
- public final String mPackageName;
- public final String mVendorID;
- public final String[] mDNSValues;
- public final int mID;
-
- public VendorInfo(Resources resources, int vendor_info_id) {
- mID = vendor_info_id;
- String[] data = resources.getStringArray(vendor_info_id);
- if ((data == null) || (data.length < 2)) {
- data = new String[] { null, null };
- }
- mPackageName = data[0];
- mVendorID = data[1];
- mDNSValues = (data.length > 2) ? Arrays.copyOfRange(data, 2, data.length) : new String[]{};
- }
-}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java
new file mode 100644
index 000000000000..c5dbc8c32e91
--- /dev/null
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java
@@ -0,0 +1,212 @@
+/*
+ * 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.content.Context;
+import android.net.nsd.NsdManager;
+import android.net.nsd.NsdServiceInfo;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+import com.android.printservice.recommendation.PrintServicePlugin;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A discovery listening for mDNS results and only adding the ones that {@link
+ * PrinterFilter#matchesCriteria match} configured list
+ */
+public class MDNSFilteredDiscovery implements NsdManager.DiscoveryListener {
+ private static final String LOG_TAG = "MDNSFilteredDiscovery";
+
+ /**
+ * mDNS service filter interface.
+ * Implement {@link PrinterFilter#matchesCriteria} to filter out supported services
+ */
+ public interface PrinterFilter {
+ /**
+ * Main filter method. Should return true if mDNS service is supported
+ * by the print service plugin
+ *
+ * @param nsdServiceInfo The service info to check
+ *
+ * @return True if service is supported by the print service plugin
+ */
+ boolean matchesCriteria(NsdServiceInfo nsdServiceInfo);
+ }
+
+ /** Printer identifiers of the mPrinters found. */
+ @GuardedBy("mLock")
+ private final @NonNull HashSet<String> mPrinters;
+
+ /** Service types discovered by this plugin */
+ private final @NonNull HashSet<String> mServiceTypes;
+
+ /** Context of the user of this plugin */
+ private final @NonNull Context mContext;
+
+ /** mDNS services filter */
+ private final @NonNull PrinterFilter mPrinterFilter;
+
+ /**
+ * Call back to report the number of mPrinters found.
+ *
+ * We assume that {@link #start} and {@link #stop} are never called in parallel, hence it is
+ * safe to not synchronize access to this field.
+ */
+ private @Nullable PrintServicePlugin.PrinterDiscoveryCallback mCallback;
+
+ /** Queue used to resolve nsd infos */
+ private final @NonNull NsdResolveQueue mResolveQueue;
+
+ /**
+ * Create new stub that assumes that a print service can be used to print on all mPrinters
+ * matching some mDNS names.
+ *
+ * @param context The context the plugin runs in
+ * @param serviceTypes The mDNS service types to listen to.
+ * @param printerFilter The filter for mDNS services
+ */
+ public MDNSFilteredDiscovery(@NonNull Context context,
+ @NonNull Set<String> serviceTypes,
+ @NonNull PrinterFilter printerFilter) {
+ mContext = Preconditions.checkNotNull(context, "context");
+ mServiceTypes = new HashSet<>(Preconditions
+ .checkCollectionNotEmpty(Preconditions.checkCollectionElementsNotNull(serviceTypes,
+ "serviceTypes"), "serviceTypes"));
+ mPrinterFilter = Preconditions.checkNotNull(printerFilter, "printerFilter");
+
+ mResolveQueue = NsdResolveQueue.getInstance();
+ mPrinters = new HashSet<>();
+ }
+
+ /**
+ * @return The NDS manager
+ */
+ private NsdManager getNDSManager() {
+ return (NsdManager) mContext.getSystemService(Context.NSD_SERVICE);
+ }
+
+ /**
+ * Start the discovery.
+ *
+ * @param callback Callbacks used by this plugin.
+ */
+ public void start(@NonNull PrintServicePlugin.PrinterDiscoveryCallback callback) {
+ mCallback = callback;
+ mCallback.onChanged(mPrinters.size());
+
+ for (String serviceType : mServiceTypes) {
+ DiscoveryListenerMultiplexer.addListener(getNDSManager(), serviceType, this);
+ }
+ }
+
+ /**
+ * Stop the discovery. This can only return once the plugin is completely finished and cleaned up.
+ */
+ public void stop() {
+ mCallback.onChanged(0);
+ mCallback = null;
+
+ for (int i = 0; i < mServiceTypes.size(); ++i) {
+ DiscoveryListenerMultiplexer.removeListener(getNDSManager(), this);
+ }
+ }
+
+ /**
+ *
+ * @return The number of discovered printers
+ */
+ public int getCount() {
+ return mPrinters.size();
+ }
+
+ @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) {
+ // empty
+ }
+
+ @Override
+ public void onDiscoveryStopped(String serviceType) {
+ mPrinters.clear();
+ }
+
+ @Override
+ public void onServiceFound(NsdServiceInfo serviceInfo) {
+ mResolveQueue.resolve(getNDSManager(), serviceInfo,
+ new NsdManager.ResolveListener() {
+ @Override
+ public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+ Log.w(LOG_TAG, "Service found: could not resolve " + serviceInfo + ": " +
+ errorCode);
+ }
+
+ @Override
+ public void onServiceResolved(NsdServiceInfo serviceInfo) {
+ if (mPrinterFilter.matchesCriteria(serviceInfo)) {
+ if (mCallback != null) {
+ boolean added = mPrinters.add(serviceInfo.getHost().getHostAddress());
+ if (added) {
+ mCallback.onChanged(mPrinters.size());
+ }
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onServiceLost(NsdServiceInfo serviceInfo) {
+ mResolveQueue.resolve(getNDSManager(), serviceInfo,
+ new NsdManager.ResolveListener() {
+ @Override
+ public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+ Log.w(LOG_TAG, "Service lost: Could not resolve " + serviceInfo + ": "
+ + errorCode);
+ }
+
+ @Override
+ public void onServiceResolved(NsdServiceInfo serviceInfo) {
+ if (mPrinterFilter.matchesCriteria(serviceInfo)) {
+ if (mCallback != null) {
+ boolean removed = mPrinters
+ .remove(serviceInfo.getHost().getHostAddress());
+
+ if (removed) {
+ mCallback.onChanged(mPrinters.size());
+ }
+ }
+ }
+ }
+ });
+ }
+} \ No newline at end of file
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSUtils.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java
index 4c27a47e144f..a6df3c8f2c24 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSUtils.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package com.android.printservice.recommendation.plugin.mdnsFilter;
+package com.android.printservice.recommendation.util;
import android.annotation.NonNull;
import android.net.nsd.NsdServiceInfo;
@@ -27,12 +27,15 @@ import java.util.Set;
/**
* Utils for dealing with mDNS attributes
*/
-class MDNSUtils {
+public class MDNSUtils {
public static final String ATTRIBUTE_TY = "ty";
public static final String ATTRIBUTE_PRODUCT = "product";
public static final String ATTRIBUTE_USB_MFG = "usb_mfg";
public static final String ATTRIBUTE_MFG = "mfg";
+ private MDNSUtils() {
+ }
+
/**
* Check if the service has any of a set of vendor names.
*
@@ -95,4 +98,35 @@ class MDNSUtils {
private static boolean containsString(@NonNull String container, @NonNull String contained) {
return container.equalsIgnoreCase(contained) || container.contains(contained + " ");
}
+
+ /**
+ * Return String from mDNS attribute byte array
+ *
+ * @param value the byte array with string data
+ *
+ * @return constructed string
+ */
+ public static String getString(byte[] value) {
+ if (value != null) return new String(value, StandardCharsets.UTF_8);
+ return null;
+ }
+
+ /**
+ * Check if service has a type of supported types set
+ *
+ * @param serviceInfo The service
+ * @param serviceTypes The supported service types set
+ *
+ * @return true if service has a type of supported types set
+ */
+ public static boolean isSupportedServiceType(@NonNull NsdServiceInfo serviceInfo,
+ @NonNull Set<String> serviceTypes) {
+ String curType = serviceInfo.getServiceType().toLowerCase();
+ for (String type : serviceTypes) {
+ if (curType.contains(type.toLowerCase())) {
+ return true;
+ }
+ }
+ return false;
+ }
}