From 784d18262da1ac00750f4f80b64a3edce7085506 Mon Sep 17 00:00:00 2001 From: Sergey Yakovlev Date: Mon, 23 May 2016 13:05:53 +0300 Subject: Samsung Printer Recommendation plugin Samsung Printer Recommendation plugin based on Printer Recommendation Example Change-Id: I26a62f103bad959418fe717dbc1a519e7ebc1337 --- SamsungPrinterRecommendation/app/build.gradle | 31 ++++ .../app/proguard-rules.pro | 17 ++ .../app/src/main/AndroidManifest.xml | 25 +++ .../discovery/recommendation/MDnsUtils.java | 74 +++++++++ .../recommendation/PrintServicePlugin.java | 71 ++++++++ .../discovery/recommendation/PrinterHashMap.java | 33 ++++ .../discovery/recommendation/ServiceListener.java | 185 +++++++++++++++++++++ .../ServiceRecommendationPlugin.java | 85 ++++++++++ .../recommendation/ServiceResolveQueue.java | 101 +++++++++++ .../discovery/recommendation/VendorInfo.java | 40 +++++ .../discovery/recommendation/DeviceList.java | 32 ++++ .../recommendation/DeviceListFragment.java | 118 +++++++++++++ .../SamsungRecommendationPlugin.java | 105 ++++++++++++ .../src/main/res/layout/activity_device_list2.xml | 20 +++ .../src/main/res/layout/content_device_list.xml | 7 + .../src/main/res/layout/fragment_device_list.xml | 11 ++ .../app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3418 bytes .../app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2206 bytes .../app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4842 bytes .../app/src/main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7718 bytes .../src/main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10486 bytes .../app/src/main/res/values-v21/styles.xml | 8 + .../app/src/main/res/values-w820dp/dimens.xml | 6 + .../app/src/main/res/values/colors.xml | 6 + .../app/src/main/res/values/dimens.xml | 5 + .../app/src/main/res/values/donottranslate.xml | 30 ++++ .../app/src/main/res/values/strings.xml | 7 + .../app/src/main/res/values/styles.xml | 17 ++ SamsungPrinterRecommendation/build.gradle | 23 +++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + SamsungPrinterRecommendation/gradlew | 164 ++++++++++++++++++ SamsungPrinterRecommendation/gradlew.bat | 90 ++++++++++ SamsungPrinterRecommendation/settings.gradle | 1 + 34 files changed, 1318 insertions(+) create mode 100644 SamsungPrinterRecommendation/app/build.gradle create mode 100644 SamsungPrinterRecommendation/app/proguard-rules.pro create mode 100644 SamsungPrinterRecommendation/app/src/main/AndroidManifest.xml create mode 100644 SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/MDnsUtils.java create mode 100644 SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/PrintServicePlugin.java create mode 100644 SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/PrinterHashMap.java create mode 100644 SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/ServiceListener.java create mode 100644 SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/ServiceRecommendationPlugin.java create mode 100644 SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/ServiceResolveQueue.java create mode 100644 SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/VendorInfo.java create mode 100644 SamsungPrinterRecommendation/app/src/main/java/com/example/android/discovery/recommendation/DeviceList.java create mode 100644 SamsungPrinterRecommendation/app/src/main/java/com/example/android/discovery/recommendation/DeviceListFragment.java create mode 100644 SamsungPrinterRecommendation/app/src/main/java/com/samsung/discovery/recommendation/SamsungRecommendationPlugin.java create mode 100644 SamsungPrinterRecommendation/app/src/main/res/layout/activity_device_list2.xml create mode 100644 SamsungPrinterRecommendation/app/src/main/res/layout/content_device_list.xml create mode 100644 SamsungPrinterRecommendation/app/src/main/res/layout/fragment_device_list.xml create mode 100644 SamsungPrinterRecommendation/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 SamsungPrinterRecommendation/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 SamsungPrinterRecommendation/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 SamsungPrinterRecommendation/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 SamsungPrinterRecommendation/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 SamsungPrinterRecommendation/app/src/main/res/values-v21/styles.xml create mode 100644 SamsungPrinterRecommendation/app/src/main/res/values-w820dp/dimens.xml create mode 100644 SamsungPrinterRecommendation/app/src/main/res/values/colors.xml create mode 100644 SamsungPrinterRecommendation/app/src/main/res/values/dimens.xml create mode 100644 SamsungPrinterRecommendation/app/src/main/res/values/donottranslate.xml create mode 100644 SamsungPrinterRecommendation/app/src/main/res/values/strings.xml create mode 100644 SamsungPrinterRecommendation/app/src/main/res/values/styles.xml create mode 100644 SamsungPrinterRecommendation/build.gradle create mode 100644 SamsungPrinterRecommendation/gradle/wrapper/gradle-wrapper.jar create mode 100644 SamsungPrinterRecommendation/gradle/wrapper/gradle-wrapper.properties create mode 100644 SamsungPrinterRecommendation/gradlew create mode 100644 SamsungPrinterRecommendation/gradlew.bat create mode 100644 SamsungPrinterRecommendation/settings.gradle diff --git a/SamsungPrinterRecommendation/app/build.gradle b/SamsungPrinterRecommendation/app/build.gradle new file mode 100644 index 0000000..1fa7cfe --- /dev/null +++ b/SamsungPrinterRecommendation/app/build.gradle @@ -0,0 +1,31 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 'android-N' + buildToolsVersion "23.0.3" + + defaultConfig { + applicationId "com.example.android.discovery.recommendation" + minSdkVersion 'N' + targetSdkVersion 'N' + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + lintOptions { + disable 'AllowBackup', 'GoogleAppIndexingWarning' + abortOnError false + checkReleaseBuilds true + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:23.3.0' + compile 'com.android.support:design:23.3.0' +} diff --git a/SamsungPrinterRecommendation/app/proguard-rules.pro b/SamsungPrinterRecommendation/app/proguard-rules.pro new file mode 100644 index 0000000..002b260 --- /dev/null +++ b/SamsungPrinterRecommendation/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /toolbox/jdelhier/android-sdk-linux/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/SamsungPrinterRecommendation/app/src/main/AndroidManifest.xml b/SamsungPrinterRecommendation/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..745ec0c --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + diff --git a/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/MDnsUtils.java b/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/MDnsUtils.java new file mode 100644 index 0000000..efc8c61 --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/MDnsUtils.java @@ -0,0 +1,74 @@ +/* + * 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.discovery.recommendation; + +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 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 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/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/PrintServicePlugin.java b/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/PrintServicePlugin.java new file mode 100644 index 0000000..68aa435 --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/PrintServicePlugin.java @@ -0,0 +1,71 @@ +/* + * 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.discovery.recommendation; + +import android.support.annotation.IntRange; +import android.support.annotation.NonNull; +import android.support.annotation.StringRes; + +/** + * Interface to be implemented by each print service plugin. + *

+ * A print service plugin is a minimal version of a real {@link android.printservice.PrintService + * print service}. You cannot print using the plugin. The only functionality in the plugin is to + * report the number of printers that the real service would discover. + */ +public interface PrintServicePlugin { + /** + * Call back used by the print service plugins. + */ + interface PrinterDiscoveryCallback { + /** + * Announce that something changed and the UI for this plugin should be updated. + * + * @param numDiscoveredPrinters The number of printers discovered. + */ + void onChanged(@IntRange(from = 0) int numDiscoveredPrinters); + } + /** + * Get the name (a string reference) of the {@link android.printservice.PrintService print + * service} with the {@link #getPackageName specified package name}. This is read once, hence + * returning different data at different times is not allowed. + * + * @return The name of the print service as a string reference. The localization is handled + * outside of the plugin. + */ + @StringRes int getName(); + /** + * The package name of the full print service. + * + * @return The package name + */ + @NonNull CharSequence getPackageName(); + /** + * Start the discovery plugin. + * + * @param callback Callbacks used by this plugin. + * + * @throws Exception If anything went wrong when starting the plugin + */ + void start(@NonNull PrinterDiscoveryCallback callback) throws Exception; + /** + * Stop the plugin. This can only return once the plugin is completely finished and cleaned up. + * + * @throws Exception If anything went wrong while stopping plugin + */ + void stop() throws Exception; +} diff --git a/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/PrinterHashMap.java b/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/PrinterHashMap.java new file mode 100644 index 0000000..e9e50d7 --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/PrinterHashMap.java @@ -0,0 +1,33 @@ +/* + * 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.discovery.recommendation; + +import android.net.nsd.NsdServiceInfo; + +import java.util.HashMap; + +public final class PrinterHashMap extends HashMap { + 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/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/ServiceListener.java b/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/ServiceListener.java new file mode 100644 index 0000000..3837a67 --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/ServiceListener.java @@ -0,0 +1,185 @@ +/* + * 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.discovery.recommendation; + +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.example.android.discovery.recommendation.R; + +public class ServiceListener implements ServiceResolveQueue.ResolveCallback { + + private final NsdManager mNSDManager; + private final Map mVendorInfoHashMap; + private final String[] mServiceType; + private final Observer mObserver; + private final ServiceResolveQueue mResolveQueue; + private List mListeners = new ArrayList<>(); + public HashMap mVendorHashMap = new HashMap<>(); + + public interface Observer { + boolean matchesCriteria(String vendor, NsdServiceInfo serviceInfo); + void dataSetChanged(); + } + + public ServiceListener(Context context, Observer observer, String[] serviceTypes) { + mResolveQueue = ServiceResolveQueue.getInstance(); + mObserver = observer; + mServiceType = serviceTypes; + mNSDManager = (NsdManager)context.getSystemService(Context.NSD_SERVICE); + + Map 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 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 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); + } + }; + mNSDManager.discoverServices(service, NsdManager.PROTOCOL_DNS_SD, listener); + mListeners.add(listener); + } + } + + public void stop() { + for(NsdManager.DiscoveryListener listener : mListeners) { + mNSDManager.stopServiceDiscovery(listener); + } + mVendorHashMap.clear(); + mListeners.clear(); + } + + public Pair getCount() { + int count = 0; + for (PrinterHashMap map : mVendorHashMap.values()) { + count += map.size(); + } + return Pair.create(mVendorHashMap.size(), count); + } +} diff --git a/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/ServiceRecommendationPlugin.java b/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/ServiceRecommendationPlugin.java new file mode 100644 index 0000000..fcb7ad0 --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/ServiceRecommendationPlugin.java @@ -0,0 +1,85 @@ +/* + * 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.discovery.recommendation; + +import android.content.Context; +import android.net.nsd.NsdManager; +import android.net.nsd.NsdServiceInfo; +import android.support.annotation.NonNull; +import android.text.TextUtils; + +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/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/ServiceResolveQueue.java b/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/ServiceResolveQueue.java new file mode 100644 index 0000000..cdfd937 --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/ServiceResolveQueue.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2006 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.discovery.recommendation; + +import android.net.nsd.NsdManager; +import android.net.nsd.NsdServiceInfo; +import android.util.Pair; + +import java.util.LinkedList; + +public final class ServiceResolveQueue { + + private final NsdManager mNsdManager; + private final LinkedList> mQueue = new LinkedList<>(); + private final Object mLock = new Object(); + + private static ServiceResolveQueue sInstance = null; + private Pair mCurrentRequest = null; + + public static void createInstance(NsdManager nsdManager) { + if (sInstance == null) sInstance = new ServiceResolveQueue(nsdManager); + } + + public static ServiceResolveQueue getInstance() { + return sInstance; + } + + public static void destroyInstance() { + sInstance = null; + } + + public interface ResolveCallback { + void serviceResolved(NsdServiceInfo nsdServiceInfo); + } + + public ServiceResolveQueue(NsdManager nsdManager) { + mNsdManager = nsdManager; + } + + public void queueRequest(NsdServiceInfo serviceInfo, ResolveCallback callback) { + synchronized (mLock) { + Pair newRequest = Pair.create(serviceInfo, callback); + if (mQueue.contains(newRequest)) return; + mQueue.add(newRequest); + makeNextRequest(); + } + } + + public void removeRequest(NsdServiceInfo serviceInfo, ResolveCallback callback) { + synchronized (mLock) { + Pair 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(); + mNsdManager.resolveService(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/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/VendorInfo.java b/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/VendorInfo.java new file mode 100644 index 0000000..595e048 --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/java/com/android/discovery/recommendation/VendorInfo.java @@ -0,0 +1,40 @@ +/* + * 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.discovery.recommendation; + +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/SamsungPrinterRecommendation/app/src/main/java/com/example/android/discovery/recommendation/DeviceList.java b/SamsungPrinterRecommendation/app/src/main/java/com/example/android/discovery/recommendation/DeviceList.java new file mode 100644 index 0000000..2eeebc4 --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/java/com/example/android/discovery/recommendation/DeviceList.java @@ -0,0 +1,32 @@ +/* + * (c) Copyright 2016 Mopria Alliance, Inc. + * + * 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.example.android.discovery.recommendation; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; + +public class DeviceList extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_device_list2); + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + } +} diff --git a/SamsungPrinterRecommendation/app/src/main/java/com/example/android/discovery/recommendation/DeviceListFragment.java b/SamsungPrinterRecommendation/app/src/main/java/com/example/android/discovery/recommendation/DeviceListFragment.java new file mode 100644 index 0000000..94a6cb5 --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/java/com/example/android/discovery/recommendation/DeviceListFragment.java @@ -0,0 +1,118 @@ +/* + * (c) Copyright 2016 Mopria Alliance, Inc. + * (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.example.android.discovery.recommendation; + +import android.content.Context; +import android.net.nsd.NsdManager; +import android.os.Bundle; +import android.support.annotation.IntRange; +import android.support.v4.app.ListFragment; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +import com.android.discovery.recommendation.PrintServicePlugin; +import com.android.discovery.recommendation.ServiceRecommendationPlugin; +import com.android.discovery.recommendation.ServiceResolveQueue; +import com.samsung.discovery.recommendation.SamsungRecommendationPlugin; + +import java.util.Locale; + +public class DeviceListFragment extends ListFragment implements PrintServicePlugin.PrinterDiscoveryCallback { + + private ArrayAdapter mArrayAdapter; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ServiceResolveQueue.createInstance((NsdManager)getActivity().getSystemService(Context.NSD_SERVICE)); + mArrayAdapter = new ArrayAdapter(getActivity(), 0) { + + class ViewHolder { + final TextView mText1; + final TextView mText2; + public ViewHolder(TextView text1, TextView text2) { + mText1 = text1; + mText2 = text2; + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view; + ViewHolder holder; + if (convertView == null) { + view = getActivity().getLayoutInflater().inflate(android.R.layout.simple_list_item_2, parent, false); + view.setTag(new ViewHolder((TextView)view.findViewById(android.R.id.text1), + (TextView)view.findViewById(android.R.id.text2))); + } else { + view = convertView; + } + holder = (ViewHolder)view.getTag(); + holder.mText1.setText(getItem(position).getName()); + holder.mText2.setText(String.format(Locale.getDefault(), "%d",getItem(position).getCount())); + return view; + } + }; + mArrayAdapter.add(new SamsungRecommendationPlugin(getActivity())); + } + + @Override + public void onDestroy() { + super.onDestroy(); + ServiceResolveQueue.destroyInstance(); + } + + + @Override + public void onResume() { + super.onResume(); + for(int i = 0; i < mArrayAdapter.getCount(); i++) { + try { + mArrayAdapter.getItem(i).start(this); + } catch(Exception ignored) {} + } + } + + @Override + public void onPause() { + super.onPause(); + for(int i = 0; i < mArrayAdapter.getCount(); i++) { + try { + mArrayAdapter.getItem(i).stop(); + } catch(Exception ignored) {} + } + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + setListAdapter(mArrayAdapter); + } + + @Override + public void onChanged(@IntRange(from = 0) int numDiscoveredPrinters) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + mArrayAdapter.notifyDataSetChanged(); + } + }); + } +} diff --git a/SamsungPrinterRecommendation/app/src/main/java/com/samsung/discovery/recommendation/SamsungRecommendationPlugin.java b/SamsungPrinterRecommendation/app/src/main/java/com/samsung/discovery/recommendation/SamsungRecommendationPlugin.java new file mode 100644 index 0000000..f5daa6a --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/java/com/samsung/discovery/recommendation/SamsungRecommendationPlugin.java @@ -0,0 +1,105 @@ +/* +(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.samsung.discovery.recommendation; + +import android.content.Context; +import android.net.nsd.NsdServiceInfo; +import android.text.TextUtils; + +import com.android.discovery.recommendation.MDnsUtils; +import com.android.discovery.recommendation.ServiceRecommendationPlugin; +import com.android.discovery.recommendation.VendorInfo; +import com.example.android.discovery.recommendation.R; + +import java.util.Locale; +import java.util.Map; + +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 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; + } +} diff --git a/SamsungPrinterRecommendation/app/src/main/res/layout/activity_device_list2.xml b/SamsungPrinterRecommendation/app/src/main/res/layout/activity_device_list2.xml new file mode 100644 index 0000000..62f06d2 --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/res/layout/activity_device_list2.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/SamsungPrinterRecommendation/app/src/main/res/layout/content_device_list.xml b/SamsungPrinterRecommendation/app/src/main/res/layout/content_device_list.xml new file mode 100644 index 0000000..67e13ed --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/res/layout/content_device_list.xml @@ -0,0 +1,7 @@ + diff --git a/SamsungPrinterRecommendation/app/src/main/res/layout/fragment_device_list.xml b/SamsungPrinterRecommendation/app/src/main/res/layout/fragment_device_list.xml new file mode 100644 index 0000000..f6820da --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/res/layout/fragment_device_list.xml @@ -0,0 +1,11 @@ + + + + diff --git a/SamsungPrinterRecommendation/app/src/main/res/mipmap-hdpi/ic_launcher.png b/SamsungPrinterRecommendation/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..cde69bc Binary files /dev/null and b/SamsungPrinterRecommendation/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/SamsungPrinterRecommendation/app/src/main/res/mipmap-mdpi/ic_launcher.png b/SamsungPrinterRecommendation/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c133a0c Binary files /dev/null and b/SamsungPrinterRecommendation/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/SamsungPrinterRecommendation/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/SamsungPrinterRecommendation/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..bfa42f0 Binary files /dev/null and b/SamsungPrinterRecommendation/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/SamsungPrinterRecommendation/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/SamsungPrinterRecommendation/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..324e72c Binary files /dev/null and b/SamsungPrinterRecommendation/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/SamsungPrinterRecommendation/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/SamsungPrinterRecommendation/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..aee44e1 Binary files /dev/null and b/SamsungPrinterRecommendation/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/SamsungPrinterRecommendation/app/src/main/res/values-v21/styles.xml b/SamsungPrinterRecommendation/app/src/main/res/values-v21/styles.xml new file mode 100644 index 0000000..65d0c39 --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/res/values-v21/styles.xml @@ -0,0 +1,8 @@ +> + + diff --git a/SamsungPrinterRecommendation/app/src/main/res/values-w820dp/dimens.xml b/SamsungPrinterRecommendation/app/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 0000000..63fc816 --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/SamsungPrinterRecommendation/app/src/main/res/values/colors.xml b/SamsungPrinterRecommendation/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..3ab3e9c --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #3F51B5 + #303F9F + #FF4081 + diff --git a/SamsungPrinterRecommendation/app/src/main/res/values/dimens.xml b/SamsungPrinterRecommendation/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..47c8224 --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 16dp + 16dp + diff --git a/SamsungPrinterRecommendation/app/src/main/res/values/donottranslate.xml b/SamsungPrinterRecommendation/app/src/main/res/values/donottranslate.xml new file mode 100644 index 0000000..1966117 --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/res/values/donottranslate.xml @@ -0,0 +1,30 @@ + + + + org.mopria.printplugin + WFDS + + + + + com.hp.android.printservice + HP + + HP + Hewlett-Packard + Hewlett Packard + + + + com.sec.app.samsungprintservice + Samsung Electronics + Samsung + + + + + @array/known_print_vendor_info_for_mopria + @array/known_print_vendor_info_for_hp + @array/known_print_vendor_info_for_samsung + + diff --git a/SamsungPrinterRecommendation/app/src/main/res/values/strings.xml b/SamsungPrinterRecommendation/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..d0af03a --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/res/values/strings.xml @@ -0,0 +1,7 @@ + + AndroidDiscovery + DeviceList + Mopria + HP + Samsung + diff --git a/SamsungPrinterRecommendation/app/src/main/res/values/styles.xml b/SamsungPrinterRecommendation/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..44f664f --- /dev/null +++ b/SamsungPrinterRecommendation/app/src/main/res/values/styles.xml @@ -0,0 +1,17 @@ + + + + + +