/* * 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.bips; import android.net.Uri; import android.print.PrinterCapabilitiesInfo; import android.print.PrinterId; import android.print.PrinterInfo; import android.util.Log; import android.widget.Toast; import com.android.bips.discovery.ConnectionListener; import com.android.bips.discovery.DiscoveredPrinter; import com.android.bips.ipp.CapabilitiesCache; import com.android.bips.jni.LocalPrinterCapabilities; import com.android.bips.p2p.P2pPrinterConnection; import com.android.bips.p2p.P2pUtils; import java.net.InetAddress; import java.util.Collections; /** * A session-specific printer record. Encapsulates logic for getting the latest printer * capabilities as necessary. */ class LocalPrinter implements CapabilitiesCache.OnLocalPrinterCapabilities { private static final String TAG = LocalPrinter.class.getSimpleName(); private static final boolean DEBUG = false; private final BuiltInPrintService mPrintService; private final LocalDiscoverySession mSession; private final PrinterId mPrinterId; private long mLastSeenTime = System.currentTimeMillis(); private boolean mFound = true; private boolean mTracking = false; private LocalPrinterCapabilities mCapabilities; private DiscoveredPrinter mDiscoveredPrinter; private P2pPrinterConnection mTrackingConnection; LocalPrinter(BuiltInPrintService printService, LocalDiscoverySession session, DiscoveredPrinter discoveredPrinter) { mPrintService = printService; mSession = session; mDiscoveredPrinter = discoveredPrinter; mPrinterId = discoveredPrinter.getId(printService); } /** Return the address of the printer or {@code null} if not known */ public InetAddress getAddress() { if (mCapabilities != null) { return mCapabilities.inetAddress; } return null; } /** Return true if this printer should be aged out */ boolean isExpired() { return !mFound && (System.currentTimeMillis() - mLastSeenTime) > LocalDiscoverySession.PRINTER_EXPIRATION_MILLIS; } /** Return capabilities or null if not present */ LocalPrinterCapabilities getCapabilities() { return mCapabilities; } /** Create a PrinterInfo from this record or null if not possible */ PrinterInfo createPrinterInfo(boolean knownGood) { if (mCapabilities == null) { if (P2pUtils.isP2p(mDiscoveredPrinter)) { // Allow user to select a P2P to establish a connection PrinterInfo.Builder builder = new PrinterInfo.Builder( mPrinterId, mDiscoveredPrinter.name, PrinterInfo.STATUS_IDLE) .setIconResourceId(R.drawable.ic_printer) .setDescription(mPrintService.getDescription(mDiscoveredPrinter)); return builder.build(); } else if (!knownGood) { // Ignore unknown LAN printers with no caps return null; } } else if (!mCapabilities.isSupported) { // Fail out if capabilities indicate not-supported. return null; } // Get the most recently discovered version of this printer DiscoveredPrinter printer = mPrintService.getDiscovery() .getPrinter(mDiscoveredPrinter.getUri()); if (printer == null) { return null; } boolean idle = mFound && mCapabilities != null; PrinterInfo.Builder builder = new PrinterInfo.Builder( mPrinterId, printer.name, idle ? PrinterInfo.STATUS_IDLE : PrinterInfo.STATUS_UNAVAILABLE) .setIconResourceId(R.drawable.ic_printer) .setDescription(mPrintService.getDescription(mDiscoveredPrinter)); if (mCapabilities != null) { // Add capabilities if we have them PrinterCapabilitiesInfo.Builder capabilitiesBuilder = new PrinterCapabilitiesInfo.Builder(mPrinterId); mCapabilities.buildCapabilities(mPrintService, capabilitiesBuilder); builder.setCapabilities(capabilitiesBuilder.build()); } return builder.build(); } @Override public void onCapabilities(LocalPrinterCapabilities capabilities) { if (mSession.isDestroyed() || !mSession.isKnown(mPrinterId)) { return; } if (capabilities == null) { if (DEBUG) Log.d(TAG, "No capabilities so removing printer " + this); mSession.removePrinters(Collections.singletonList(mPrinterId)); } else { mCapabilities = capabilities; mSession.handlePrinter(this); } } PrinterId getPrinterId() { return mPrinterId; } /** Return true if the printer is in a "found" state according to discoveries */ boolean isFound() { return mFound; } /** * Indicate the printer was found and gather capabilities if we don't have them */ void found(DiscoveredPrinter printer) { mDiscoveredPrinter = printer; mLastSeenTime = System.currentTimeMillis(); mFound = true; // Check for cached capabilities LocalPrinterCapabilities capabilities = mPrintService.getCapabilitiesCache() .get(mDiscoveredPrinter); if (capabilities != null) { // Report current capabilities onCapabilities(capabilities); } else { // Announce printer and fetch capabilities immediately if possible mSession.handlePrinter(this); if (!P2pUtils.isP2p(mDiscoveredPrinter)) { mPrintService.getCapabilitiesCache().request(mDiscoveredPrinter, mSession.isPriority(mPrinterId), this); } else if (mTracking) { startTracking(); } } } /** * Begin tracking (getting latest capabilities) for this printer */ public void track() { if (DEBUG) Log.d(TAG, "track " + mDiscoveredPrinter); startTracking(); } private void startTracking() { mTracking = true; if (mTrackingConnection != null) { return; } // For any P2P printer, obtain a connection if (P2pUtils.isP2p(mDiscoveredPrinter) || P2pUtils.isOnConnectedInterface(mPrintService, mDiscoveredPrinter)) { ConnectionListener listener = new ConnectionListener() { @Override public void onConnectionComplete(DiscoveredPrinter printer) { if (DEBUG) Log.d(TAG, "connection complete " + printer); if (printer == null) { mTrackingConnection = null; } } @Override public void onConnectionDelayed(boolean delayed) { if (DEBUG) Log.d(TAG, "connection delayed=" + delayed); if (delayed) { Toast.makeText(mPrintService, R.string.connect_hint_text, Toast.LENGTH_LONG).show(); } } }; mTrackingConnection = new P2pPrinterConnection(mPrintService, mDiscoveredPrinter, listener); } } /** * Stop tracking this printer */ void stopTracking() { if (mTrackingConnection != null) { mTrackingConnection.close(); mTrackingConnection = null; } mTracking = false; } /** * Mark this printer as not found (will eventually expire) */ void notFound() { mFound = false; mLastSeenTime = System.currentTimeMillis(); } /** Return the UUID for this printer if it is known */ public Uri getUuid() { return mDiscoveredPrinter.uuid; } @Override public String toString() { return mDiscoveredPrinter.toString(); } }