diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2018-01-20 06:04:25 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2018-01-20 06:04:25 +0000 |
commit | b8acc5fdacb470100f1f66b530cc4e399723a725 (patch) | |
tree | 55c181aab2781a109c10b26916a1e6975f9560dc | |
parent | d123b55e609eb4b6732f59c94ea79210dc3ec10d (diff) | |
parent | 1e326d3a8ef665536a542f0ed64112dbe00a03c6 (diff) | |
download | BuiltInPrintService-o-mr1-iot-preview-7.tar.gz |
Merge "Support manual-add of IPPS and other printers"android-wear-8.0.0_r1android-p-preview-1android-o-mr1-iot-preview-8android-o-mr1-iot-preview-7o-mr1-iot-preview-8o-mr1-iot-preview-7
-rw-r--r-- | src/com/android/bips/discovery/ManualDiscovery.java | 89 | ||||
-rw-r--r-- | src/com/android/bips/ipp/Backend.java | 8 | ||||
-rw-r--r-- | src/com/android/bips/ipp/CapabilitiesCache.java | 4 | ||||
-rw-r--r-- | src/com/android/bips/ipp/GetCapabilitiesTask.java | 19 | ||||
-rw-r--r-- | src/com/android/bips/ui/AddManualPrinterDialog.java | 73 | ||||
-rw-r--r-- | src/com/android/bips/ui/AddPrintersFragment.java | 2 |
6 files changed, 142 insertions, 53 deletions
diff --git a/src/com/android/bips/discovery/ManualDiscovery.java b/src/com/android/bips/discovery/ManualDiscovery.java index 083844c..4b8f9a1 100644 --- a/src/com/android/bips/discovery/ManualDiscovery.java +++ b/src/com/android/bips/discovery/ManualDiscovery.java @@ -27,7 +27,10 @@ import com.android.bips.jni.LocalPrinterCapabilities; import com.android.bips.util.WifiMonitor; import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; /** * Manage a list of printers manually added by the user. @@ -37,12 +40,15 @@ public class ManualDiscovery extends SavedDiscovery { private static final boolean DEBUG = false; // Likely paths at which a print service may be found - private static final Uri[] IPP_URIS = {Uri.parse("ipp://path:631/ipp/print"), - Uri.parse("ipp://path:80/ipp/print"), Uri.parse("ipp://path:631/ipp/printer"), - Uri.parse("ipp://path:631/ipp"), Uri.parse("ipp://path:631/")}; + private static final Uri[] IPP_URIS = {Uri.parse("ipp://host:631/ipp/print"), + Uri.parse("ipp://host:80/ipp/print"), Uri.parse("ipp://host:631/ipp/printer"), + Uri.parse("ipp://host:631/ipp"), Uri.parse("ipp://host:631/"), + Uri.parse("ipps://host:631/ipp/print"), Uri.parse("ipps://host:443/ipp/print"), + Uri.parse("ipps://host:10443/ipp/print")}; private WifiMonitor mWifiMonitor; private CapabilitiesCache mCapabilitiesCache; + private List<CapabilitiesFinder> mAddRequests = new ArrayList<>(); public ManualDiscovery(BuiltInPrintService printService) { super(printService); @@ -77,11 +83,54 @@ public class ManualDiscovery extends SavedDiscovery { } /** - * Asynchronously attempt to add a new manual printer, calling back with success + * Asynchronously attempt to add a new manual printer, calling back with success if + * printer capabilities were discovered. + * + * The supplied URI must include a hostname and may also include a scheme (either ipp:// or + * ipps://), a port (such as :443), and/or a path (like /ipp/print). If any parts are missing, + * typical known values are substituted and searched until success is found, or all are + * tried unsuccessfully. + * + * @param printerUri URI to search */ - public void addManualPrinter(String hostname, PrinterAddCallback callback) { - if (DEBUG) Log.d(TAG, "addManualPrinter " + hostname); - new CapabilitiesFinder(hostname, callback); + public void addManualPrinter(Uri printerUri, PrinterAddCallback callback) { + if (DEBUG) Log.d(TAG, "addManualPrinter " + printerUri); + + int givenPort = printerUri.getPort(); + String givenPath = printerUri.getPath(); + String hostname = printerUri.getHost(); + String givenScheme = printerUri.getScheme(); + + // Use LinkedHashSet to eliminate duplicates but maintain order + Set<Uri> uris = new LinkedHashSet<>(); + for (Uri uri : IPP_URIS) { + String scheme = uri.getScheme(); + if (!TextUtils.isEmpty(givenScheme) && !scheme.equals(givenScheme)) { + // If scheme was supplied and doesn't match this uri template, skip + continue; + } + String authority = hostname + ":" + (givenPort == -1 ? uri.getPort() : givenPort); + String path = TextUtils.isEmpty(givenPath) ? uri.getPath() : givenPath; + Uri targetUri = uri.buildUpon().scheme(scheme).encodedAuthority(authority).path(path) + .build(); + uris.add(targetUri); + } + + mAddRequests.add(new CapabilitiesFinder(uris, callback)); + } + + /** + * Cancel a prior {@link #addManualPrinter(Uri, PrinterAddCallback)} attempt having the same + * callback + */ + public void cancelAddManualPrinter(PrinterAddCallback callback) { + for (CapabilitiesFinder finder : mAddRequests) { + if (finder.mFinalCallback == callback) { + mAddRequests.remove(finder); + finder.cancel(); + return; + } + } } /** Used to convey response to {@link #addManualPrinter} */ @@ -113,27 +162,26 @@ public class ManualDiscovery extends SavedDiscovery { /** * Constructs a new finder * - * @param hostname Hostname to crawl for IPP endpoints + * @param uris Locations to check for IPP endpoints * @param callback Callback to issue when the first successful response arrives, or * when all responses have failed. */ - CapabilitiesFinder(String hostname, PrinterAddCallback callback) { + CapabilitiesFinder(Collection<Uri> uris, PrinterAddCallback callback) { mFinalCallback = callback; - - for (Uri uri : IPP_URIS) { - Uri printerPath = uri.buildUpon().encodedAuthority(hostname + ":" + uri.getPort()) - .build(); + for (Uri uri : uris) { CapabilitiesCache.OnLocalPrinterCapabilities capabilitiesCallback = new CapabilitiesCache.OnLocalPrinterCapabilities() { @Override public void onCapabilities(LocalPrinterCapabilities capabilities) { mRequests.remove(this); - handleCapabilities(printerPath, capabilities); + handleCapabilities(uri, capabilities); } }; mRequests.add(capabilitiesCallback); - mCapabilitiesCache.request(new DiscoveredPrinter(null, "", printerPath, null), + // Force a clean attempt from scratch + mCapabilitiesCache.remove(uri); + mCapabilitiesCache.request(new DiscoveredPrinter(null, "", uri, null), true, capabilitiesCallback); } } @@ -144,6 +192,7 @@ public class ManualDiscovery extends SavedDiscovery { if (capabilities == null) { if (mRequests.isEmpty()) { + mAddRequests.remove(this); mFinalCallback.onNotFound(); } return; @@ -169,8 +218,16 @@ public class ManualDiscovery extends SavedDiscovery { printerFound(resolvedPrinter); } } - + mAddRequests.remove(this); mFinalCallback.onFound(resolvedPrinter, capabilities.isSupported); } + + /** Stop all in-progress capability requests that are in progress */ + public void cancel() { + for (CapabilitiesCache.OnLocalPrinterCapabilities callback : mRequests) { + mCapabilitiesCache.cancel(callback); + } + mRequests.clear(); + } } } diff --git a/src/com/android/bips/ipp/Backend.java b/src/com/android/bips/ipp/Backend.java index b3eed0f..94d6a11 100644 --- a/src/com/android/bips/ipp/Backend.java +++ b/src/com/android/bips/ipp/Backend.java @@ -89,16 +89,18 @@ public class Backend implements JobCallback { } /** Asynchronously get printer capabilities, returning results or null to a callback */ - public AsyncTask<?, ?, ?> getCapabilities(Uri uri, long timeout, boolean highPriority, + public GetCapabilitiesTask getCapabilities(Uri uri, long timeout, boolean highPriority, final Consumer<LocalPrinterCapabilities> capabilitiesConsumer) { if (DEBUG) Log.d(TAG, "getCapabilities()"); - return new GetCapabilitiesTask(this, uri, timeout, highPriority) { + GetCapabilitiesTask task = new GetCapabilitiesTask(this, uri, timeout, highPriority) { @Override protected void onPostExecute(LocalPrinterCapabilities result) { capabilitiesConsumer.accept(result); } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }; + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + return task; } /** diff --git a/src/com/android/bips/ipp/CapabilitiesCache.java b/src/com/android/bips/ipp/CapabilitiesCache.java index 6f51dee..dd4d258 100644 --- a/src/com/android/bips/ipp/CapabilitiesCache.java +++ b/src/com/android/bips/ipp/CapabilitiesCache.java @@ -230,7 +230,7 @@ public class CapabilitiesCache extends LruCache<Uri, LocalPrinterCapabilities> i public class Request implements Consumer<LocalPrinterCapabilities> { final DiscoveredPrinter mPrinter; final List<OnLocalPrinterCapabilities> mCallbacks = new ArrayList<>(); - AsyncTask<?, ?, ?> mQuery; + GetCapabilitiesTask mQuery; boolean mHighPriority = false; long mTimeout; @@ -245,7 +245,7 @@ public class CapabilitiesCache extends LruCache<Uri, LocalPrinterCapabilities> i private void cancel() { if (mQuery != null) { - mQuery.cancel(true); + mQuery.forceCancel(); mQuery = null; } } diff --git a/src/com/android/bips/ipp/GetCapabilitiesTask.java b/src/com/android/bips/ipp/GetCapabilitiesTask.java index 762390e..987e917 100644 --- a/src/com/android/bips/ipp/GetCapabilitiesTask.java +++ b/src/com/android/bips/ipp/GetCapabilitiesTask.java @@ -32,7 +32,7 @@ import java.net.Socket; import java.net.UnknownHostException; /** A background task that queries a specific URI for its complete capabilities */ -class GetCapabilitiesTask extends AsyncTask<Void, Void, LocalPrinterCapabilities> { +public class GetCapabilitiesTask extends AsyncTask<Void, Void, LocalPrinterCapabilities> { private static final String TAG = GetCapabilitiesTask.class.getSimpleName(); private static final boolean DEBUG = false; @@ -43,6 +43,7 @@ class GetCapabilitiesTask extends AsyncTask<Void, Void, LocalPrinterCapabilities private final Uri mUri; private final long mTimeout; private final boolean mPriority; + private volatile Socket mSocket; GetCapabilitiesTask(Backend backend, Uri uri, long timeout, boolean priority) { mUri = uri; @@ -53,11 +54,27 @@ class GetCapabilitiesTask extends AsyncTask<Void, Void, LocalPrinterCapabilities private boolean isDeviceOnline(Uri uri) { try (Socket socket = new Socket()) { + mSocket = socket; InetSocketAddress a = new InetSocketAddress(uri.getHost(), uri.getPort()); socket.connect(a, (int) mTimeout); return true; } catch (IOException e) { return false; + } finally { + mSocket = null; + } + } + + /** Forcibly cancel this task, including stopping any socket that was opened */ + public void forceCancel() { + cancel(true); + Socket socket = mSocket; + if (socket != null) { + try { + socket.close(); + } catch (IOException e) { + // Ignored + } } } diff --git a/src/com/android/bips/ui/AddManualPrinterDialog.java b/src/com/android/bips/ui/AddManualPrinterDialog.java index 5699b15..a46f5fd 100644 --- a/src/com/android/bips/ui/AddManualPrinterDialog.java +++ b/src/com/android/bips/ui/AddManualPrinterDialog.java @@ -21,6 +21,7 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; +import android.net.Uri; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; @@ -46,18 +47,17 @@ import java.util.regex.Pattern; * Allows the user to enter printer address manually */ class AddManualPrinterDialog extends AlertDialog implements TextWatcher, - TextView.OnEditorActionListener, View.OnKeyListener { + TextView.OnEditorActionListener, View.OnKeyListener, ManualDiscovery.PrinterAddCallback { private static final String TAG = AddManualPrinterDialog.class.getSimpleName(); private static final boolean DEBUG = false; /** - * A regex that matches IP addresses and domain names like "192.168.1.101" and - * "printer1.company.com" + * A regex matching any printer URI with optional protocol, port and path. */ - private static final String NAME_IP_REGEX = - "[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*"; - private static final String HOSTNAME_REGEXP = "^" + NAME_IP_REGEX + "$"; - private static final Pattern HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP); + private static final String URI_REGEX = + "(ipp[s]?://)?[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*(:[0-9]+)?(/.*)?"; + private static final String FULL_URI_REGEX = "^" + URI_REGEX + "$"; + private static final Pattern FULL_URI_PATTERN = Pattern.compile(FULL_URI_REGEX); private final ManualDiscovery mDiscovery; private final Activity mActivity; @@ -85,8 +85,8 @@ class AddManualPrinterDialog extends AlertDialog implements TextWatcher, super.onCreate(savedInstanceState); mAddButton = getButton(AlertDialog.BUTTON_POSITIVE); - mHostnameView = (TextView) findViewById(R.id.hostname); - mProgressBar = (ProgressBar) findViewById(R.id.progress); + mHostnameView = findViewById(R.id.hostname); + mProgressBar = findViewById(R.id.progress); mAddButton.setOnClickListener(view1 -> addPrinter()); @@ -101,6 +101,13 @@ class AddManualPrinterDialog extends AlertDialog implements TextWatcher, updateButtonState(); } + @Override + protected void onStop() { + if (DEBUG) Log.d(TAG, "onStop()"); + super.onStop(); + mDiscovery.cancelAddManualPrinter(this); + } + private void openKeyboard(TextView view) { Window window = getWindow(); if (window != null) { @@ -115,9 +122,8 @@ class AddManualPrinterDialog extends AlertDialog implements TextWatcher, private void updateButtonState() { String hostname = mHostnameView.getText().toString(); - Matcher hostMatch = HOSTNAME_PATTERN.matcher(hostname); - - mAddButton.setEnabled(hostMatch.matches()); + Matcher uriMatcher = FULL_URI_PATTERN.matcher(hostname); + mAddButton.setEnabled(uriMatcher.matches()); } /** Attempt to add the printer based on current data */ @@ -128,24 +134,31 @@ class AddManualPrinterDialog extends AlertDialog implements TextWatcher, mProgressBar.setVisibility(View.VISIBLE); // Begin an attempt to add the printer - mDiscovery.addManualPrinter(mHostnameView.getText().toString(), - new ManualDiscovery.PrinterAddCallback() { - @Override - public void onFound(DiscoveredPrinter printer, boolean supported) { - if (supported) { - // Success case - dismiss(); - mActivity.finish(); - } else { - error(getContext().getString(R.string.printer_not_supported)); - } - } - - @Override - public void onNotFound() { - error(getContext().getString(R.string.no_printer_found)); - } - }); + String uriString = mHostnameView.getText().toString(); + Uri printerUri; + if (uriString.contains("://")) { + printerUri = Uri.parse(uriString); + } else { + // create a schemeless URI + printerUri = Uri.parse("://" + uriString); + } + mDiscovery.addManualPrinter(printerUri, this); + } + + @Override + public void onFound(DiscoveredPrinter printer, boolean supported) { + if (supported) { + // Success case + dismiss(); + mActivity.finish(); + } else { + error(getContext().getString(R.string.printer_not_supported)); + } + } + + @Override + public void onNotFound() { + error(getContext().getString(R.string.no_printer_found)); } /** Inform user of error and allow them to correct it */ diff --git a/src/com/android/bips/ui/AddPrintersFragment.java b/src/com/android/bips/ui/AddPrintersFragment.java index dc7b73e..7b51447 100644 --- a/src/com/android/bips/ui/AddPrintersFragment.java +++ b/src/com/android/bips/ui/AddPrintersFragment.java @@ -143,7 +143,7 @@ public class AddPrintersFragment extends PreferenceFragment implements ServiceCo if (P2pUtils.isP2p(printer)) { message = mPrintService.getString(R.string.connects_via_wifi_direct); } else { - message = mPrintService.getString(R.string.connects_via_network, printer.getHost()); + message = mPrintService.getString(R.string.connects_via_network, printer.path); } new AlertDialog.Builder(getContext()) .setTitle(printer.name) |