Add RecommendationPlugin for Cloud Print
Reuses already existing infrastructure. The mMDNSFilteredDiscovery lambda
is called for every network service that supports #PRIVET_SERVICE. Then
the plugin checks the txt fields to make sure the printer is valid. The
check is not complete but good enough to make sure this is either a
cloud print capable printer or something that tries really hard.
Test: Connected to network with three printers, 2 GCP capable. Found the
two printers
Fixes: 35766193
Change-Id: I7c9180c8c154fa092fec5b943a94bad77da74c86
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="plugin_vendor_google_cloud_print">Cloud Print</string>
|
||||
<string name="plugin_vendor_hp">HP</string>
|
||||
<string name="plugin_vendor_lexmark">Lexmark</string>
|
||||
<string name="plugin_vendor_brother">Brother</string>
|
||||
|
||||
@@ -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;
|
||||
@@ -60,6 +62,14 @@ public class RecommendationServiceImpl extends RecommendationService
|
||||
new RuntimeException("Could not parse vendorconfig", e);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user