1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  * Copyright (C) 2016 Mopria Alliance, Inc.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package com.android.bips;
19 
20 import android.net.Uri;
21 import android.print.PrinterCapabilitiesInfo;
22 import android.print.PrinterId;
23 import android.print.PrinterInfo;
24 import android.util.Log;
25 
26 import com.android.bips.discovery.DiscoveredPrinter;
27 import com.android.bips.ipp.CapabilitiesCache;
28 import com.android.bips.jni.LocalPrinterCapabilities;
29 
30 import java.net.InetAddress;
31 import java.net.UnknownHostException;
32 import java.util.Collections;
33 
34 /**
35  * A session-specific printer record. Encapsulates logic for getting the latest printer
36  * capabilities as necessary.
37  */
38 class LocalPrinter implements CapabilitiesCache.OnLocalPrinterCapabilities {
39     private static final String TAG = LocalPrinter.class.getSimpleName();
40     private static final boolean DEBUG = false;
41 
42     private final BuiltInPrintService mPrintService;
43     private final DiscoveredPrinter mDiscoveredPrinter;
44     private final LocalDiscoverySession mSession;
45     private final PrinterId mPrinterId;
46     private long mLastSeenTime = System.currentTimeMillis();
47     private boolean mFound = true;
48     private LocalPrinterCapabilities mCapabilities;
49 
LocalPrinter(BuiltInPrintService printService, LocalDiscoverySession session, DiscoveredPrinter discoveredPrinter)50     LocalPrinter(BuiltInPrintService printService, LocalDiscoverySession session,
51             DiscoveredPrinter discoveredPrinter) {
52         mPrintService = printService;
53         mSession = session;
54         mDiscoveredPrinter = discoveredPrinter;
55         mPrinterId = discoveredPrinter.getId(printService);
56     }
57 
58     /**
59      * @return The address of the printer or {@code null} if the printer is not reachable
60      *
61      * @throws UnknownHostException if the address could not be resolved
62      */
getAddress()63     public InetAddress getAddress() throws UnknownHostException {
64         return InetAddress.getByName(mDiscoveredPrinter.path.getHost());
65     }
66 
67     /** Return true if this printer should be aged out */
isExpired()68     boolean isExpired() {
69         return !mFound && (System.currentTimeMillis() - mLastSeenTime) >
70                 LocalDiscoverySession.PRINTER_EXPIRATION_MILLIS;
71     }
72 
73     /** Return capabilities or null if not present */
getCapabilities()74     LocalPrinterCapabilities getCapabilities() {
75         return mCapabilities;
76     }
77 
78     /** Create a PrinterInfo from this record or null if not possible */
createPrinterInfo()79     PrinterInfo createPrinterInfo() {
80         if (mCapabilities != null && !mCapabilities.isSupported) {
81             // Fail out if not supported.
82             return null;
83         }
84 
85         String description = mDiscoveredPrinter.getDescription(mPrintService);
86         boolean idle = mFound && mCapabilities != null;
87         PrinterInfo.Builder builder = new PrinterInfo.Builder(
88                 mPrinterId, mDiscoveredPrinter.name,
89                 idle ? PrinterInfo.STATUS_IDLE : PrinterInfo.STATUS_UNAVAILABLE)
90                 .setIconResourceId(R.drawable.ic_printer)
91                 .setDescription(description);
92 
93         if (mCapabilities != null) {
94             // Add capabilities if we have them
95             PrinterCapabilitiesInfo.Builder capabilitiesBuilder =
96                     new PrinterCapabilitiesInfo.Builder(mPrinterId);
97             mCapabilities.buildCapabilities(mPrintService, capabilitiesBuilder);
98             builder.setCapabilities(capabilitiesBuilder.build());
99         }
100 
101         return builder.build();
102     }
103 
104     @Override
onCapabilities(LocalPrinterCapabilities capabilities)105     public void onCapabilities(LocalPrinterCapabilities capabilities) {
106         if (mSession.isDestroyed() || !mSession.isKnown(mPrinterId)) return;
107 
108         if (capabilities == null) {
109             if (DEBUG) Log.d(TAG, "No capabilities so removing printer " + this);
110             mSession.removePrinters(Collections.singletonList(mPrinterId));
111         } else {
112             mCapabilities = capabilities;
113             mSession.handlePrinter(this);
114         }
115     }
116 
getPrinterId()117     PrinterId getPrinterId() {
118         return mPrinterId;
119     }
120 
121     /** Return true if the printer is in a "found" state according to discoveries */
isFound()122     boolean isFound() {
123         return mFound;
124     }
125 
126     /** Start a fresh request for capabilities */
requestCapabilities()127     void requestCapabilities() {
128         mPrintService.getCapabilitiesCache().request(mDiscoveredPrinter,
129                 mSession.isPriority(mPrinterId), this);
130     }
131 
132     /**
133      * Indicate the printer was found and gather capabilities if we don't have them
134      */
found()135     void found() {
136         mLastSeenTime = System.currentTimeMillis();
137         mFound = true;
138 
139         // Check for cached capabilities
140         Uri printerUri = mDiscoveredPrinter.getUri();
141         LocalPrinterCapabilities capabilities = mPrintService.getCapabilitiesCache()
142                 .get(printerUri);
143         if (DEBUG) Log.d(TAG, "Printer " + mDiscoveredPrinter + " has caps=" + capabilities);
144 
145         if (capabilities != null) {
146             // Report current capabilities
147             onCapabilities(capabilities);
148         } else {
149             // Announce printer and fetch capabilities
150             mSession.handlePrinter(this);
151             requestCapabilities();
152         }
153     }
154 
155     /**
156      * Mark this printer as not found (will eventually expire)
157      */
notFound()158     void notFound() {
159         mFound = false;
160         mLastSeenTime = System.currentTimeMillis();
161     }
162 
163     /** Return the UUID for this printer if it is known */
getUuid()164     public Uri getUuid() {
165         return mDiscoveredPrinter.uuid;
166     }
167 
168     @Override
toString()169     public String toString() {
170         return mDiscoveredPrinter.toString();
171     }
172 }