diff options
author | Philip P. Moltmann <moltmann@google.com> | 2017-04-06 20:49:53 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2017-04-06 20:49:53 +0000 |
commit | 3b817ad66c8afd2e05259ced23289c69f658669e (patch) | |
tree | 2af402a10a44bc0d6d8e4e6cc4c4c1b8a8b370d6 /packages/PrintRecommendationService/src | |
parent | ca53b1fcfe05ddde8778eebaf2efe72a7d7072d3 (diff) | |
parent | 41687d06f4de2eb76f12111a4fc7d03a4e171f2c (diff) |
Merge "Add RecommendationPlugin for Cloud Print" am: b2c75d062d am: 997f7cbabf
am: 41687d06f4
Change-Id: Iddb64b94c03eaf6925d9b4e161ac3c6fdd25a1b8
Diffstat (limited to 'packages/PrintRecommendationService/src')
2 files changed, 178 insertions, 0 deletions
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java index d0483962eae3..9436bd200f19 100644 --- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java +++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java @@ -21,6 +21,8 @@ import android.printservice.recommendation.RecommendationInfo; import android.printservice.recommendation.RecommendationService; import android.printservice.PrintService; import android.util.Log; + +import com.android.printservice.recommendation.plugin.google.CloudPrintPlugin; import com.android.printservice.recommendation.plugin.hp.HPRecommendationPlugin; import com.android.printservice.recommendation.plugin.mdnsFilter.MDNSFilterPlugin; import com.android.printservice.recommendation.plugin.mdnsFilter.VendorConfig; @@ -61,6 +63,14 @@ public class RecommendationServiceImpl extends RecommendationService } try { + mPlugins.add(new RemotePrintServicePlugin(new CloudPrintPlugin(this), this, + true)); + } catch (Exception e) { + Log.e(LOG_TAG, "Could not initiate " + + getString(R.string.plugin_vendor_google_cloud_print) + " plugin", e); + } + + try { mPlugins.add(new RemotePrintServicePlugin(new HPRecommendationPlugin(this), this, false)); } catch (Exception e) { diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/google/CloudPrintPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/google/CloudPrintPlugin.java new file mode 100644 index 000000000000..05b0c862ebd5 --- /dev/null +++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/google/CloudPrintPlugin.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2017 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.google; + +import static com.android.printservice.recommendation.util.MDNSUtils.ATTRIBUTE_TY; + +import android.annotation.NonNull; +import android.annotation.StringRes; +import android.content.Context; +import android.util.ArrayMap; +import android.util.Log; + +import com.android.printservice.recommendation.PrintServicePlugin; +import com.android.printservice.recommendation.R; +import com.android.printservice.recommendation.util.MDNSFilteredDiscovery; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Plugin detecting <a href="https://developers.google.com/cloud-print/docs/privet">Google Cloud + * Print</a> printers. + */ +public class CloudPrintPlugin implements PrintServicePlugin { + private static final String LOG_TAG = CloudPrintPlugin.class.getSimpleName(); + private static final boolean DEBUG = false; + + private static final String ATTRIBUTE_TXTVERS = "txtvers"; + private static final String ATTRIBUTE_URL = "url"; + private static final String ATTRIBUTE_TYPE = "type"; + private static final String ATTRIBUTE_ID = "id"; + private static final String ATTRIBUTE_CS = "cs"; + + private static final String TYPE = "printer"; + + private static final String PRIVET_SERVICE = "_privet._tcp"; + + /** The required mDNS service types */ + private static final Set<String> PRINTER_SERVICE_TYPE = new HashSet<String>() {{ + // Not checking _printer_._sub + add(PRIVET_SERVICE); + }}; + + /** All possible connection states */ + private static final Set<String> POSSIBLE_CONNECTION_STATES = new HashSet<String>() {{ + add("online"); + add("offline"); + add("connecting"); + add("not-configured"); + }}; + + private static final byte SUPPORTED_TXTVERS = '1'; + + /** The mDNS filtered discovery */ + private final MDNSFilteredDiscovery mMDNSFilteredDiscovery; + + /** + * Create a plugin detecting Google Cloud Print printers. + * + * @param context The context the plugin runs in + */ + public CloudPrintPlugin(@NonNull Context context) { + mMDNSFilteredDiscovery = new MDNSFilteredDiscovery(context, PRINTER_SERVICE_TYPE, + nsdServiceInfo -> { + // The attributes are case insensitive. For faster searching create a clone of + // the map with the attribute-keys all in lower case. + ArrayMap<String, byte[]> caseInsensitiveAttributes = + new ArrayMap<>(nsdServiceInfo.getAttributes().size()); + for (Map.Entry<String, byte[]> entry : nsdServiceInfo.getAttributes() + .entrySet()) { + caseInsensitiveAttributes.put(entry.getKey().toLowerCase(), + entry.getValue()); + } + + if (DEBUG) { + Log.i(LOG_TAG, nsdServiceInfo.getServiceName() + ":"); + Log.i(LOG_TAG, "type: " + nsdServiceInfo.getServiceType()); + Log.i(LOG_TAG, "host: " + nsdServiceInfo.getHost()); + for (Map.Entry<String, byte[]> entry : caseInsensitiveAttributes.entrySet()) { + if (entry.getValue() == null) { + Log.i(LOG_TAG, entry.getKey() + "= null"); + } else { + Log.i(LOG_TAG, entry.getKey() + "=" + new String(entry.getValue(), + StandardCharsets.UTF_8)); + } + } + } + + byte[] txtvers = caseInsensitiveAttributes.get(ATTRIBUTE_TXTVERS); + if (txtvers == null || txtvers.length != 1 || txtvers[0] != SUPPORTED_TXTVERS) { + // The spec requires this to be the first attribute, but at this time we + // lost the order of the attributes + return false; + } + + if (caseInsensitiveAttributes.get(ATTRIBUTE_TY) == null) { + return false; + } + + byte[] url = caseInsensitiveAttributes.get(ATTRIBUTE_URL); + if (url == null || url.length == 0) { + return false; + } + + byte[] type = caseInsensitiveAttributes.get(ATTRIBUTE_TYPE); + if (type == null || !TYPE.equals( + new String(type, StandardCharsets.UTF_8).toLowerCase())) { + return false; + } + + if (caseInsensitiveAttributes.get(ATTRIBUTE_ID) == null) { + return false; + } + + byte[] cs = caseInsensitiveAttributes.get(ATTRIBUTE_CS); + if (cs == null || !POSSIBLE_CONNECTION_STATES.contains( + new String(cs, StandardCharsets.UTF_8).toLowerCase())) { + return false; + } + + InetAddress address = nsdServiceInfo.getHost(); + if (!(address instanceof Inet4Address)) { + // Not checking for link local address + return false; + } + + return true; + }); + } + + @Override + @NonNull public CharSequence getPackageName() { + return "com.google.android.apps.cloudprint"; + } + + @Override + public void start(@NonNull PrinterDiscoveryCallback callback) throws Exception { + mMDNSFilteredDiscovery.start(callback); + } + + @Override + @StringRes public int getName() { + return R.string.plugin_vendor_google_cloud_print; + } + + @Override + public void stop() throws Exception { + mMDNSFilteredDiscovery.stop(); + } +} |