blob: abb441b79bc10a2eb4fae819d6e00c25eb68f124 [file] [log] [blame]
Svetoslav Ganov44720af2013-08-20 16:32:53 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.print;
18
19import android.content.Context;
Svetoslav2fbd2a72013-09-16 17:53:51 -070020import android.content.pm.ParceledListSlice;
Svetoslav Ganov44720af2013-08-20 16:32:53 -070021import android.os.Handler;
22import android.os.Looper;
23import android.os.Message;
24import android.os.RemoteException;
25import android.util.ArrayMap;
26import android.util.Log;
27
28import java.lang.ref.WeakReference;
29import java.util.ArrayList;
30import java.util.Collections;
Svetoslav Ganovcfab2452013-09-28 12:09:23 -070031import java.util.LinkedHashMap;
Svetoslav Ganov44720af2013-08-20 16:32:53 -070032import java.util.List;
33
34/**
35 * @hide
36 */
37public final class PrinterDiscoverySession {
38
39 private static final String LOG_TAG ="PrinterDiscoverySession";
40
41 private static final int MSG_PRINTERS_ADDED = 1;
42 private static final int MSG_PRINTERS_REMOVED = 2;
Svetoslav Ganov44720af2013-08-20 16:32:53 -070043
Svetoslav Ganovcfab2452013-09-28 12:09:23 -070044 private final LinkedHashMap<PrinterId, PrinterInfo> mPrinters =
45 new LinkedHashMap<PrinterId, PrinterInfo>();
Svetoslav Ganov44720af2013-08-20 16:32:53 -070046
47 private final IPrintManager mPrintManager;
48
49 private final int mUserId;
50
51 private final Handler mHandler;
52
53 private IPrinterDiscoveryObserver mObserver;
54
55 private OnPrintersChangeListener mListener;
56
57 private boolean mIsPrinterDiscoveryStarted;
58
59 public static interface OnPrintersChangeListener {
60 public void onPrintersChanged();
61 }
62
63 PrinterDiscoverySession(IPrintManager printManager, Context context, int userId) {
64 mPrintManager = printManager;
65 mUserId = userId;
66 mHandler = new SessionHandler(context.getMainLooper());
67 mObserver = new PrinterDiscoveryObserver(this);
68 try {
69 mPrintManager.createPrinterDiscoverySession(mObserver, mUserId);
70 } catch (RemoteException re) {
71 Log.e(LOG_TAG, "Error creating printer discovery session", re);
72 }
73 }
74
Svetoslava798c0a2014-05-15 10:47:19 -070075 public final void startPrinterDiscovery(List<PrinterId> priorityList) {
Svetoslav Ganov44720af2013-08-20 16:32:53 -070076 if (isDestroyed()) {
Svetoslava798c0a2014-05-15 10:47:19 -070077 Log.w(LOG_TAG, "Ignoring start printers discovery - session destroyed");
Svetoslav Ganovd26d4892013-08-28 14:37:54 -070078 return;
Svetoslav Ganov44720af2013-08-20 16:32:53 -070079 }
80 if (!mIsPrinterDiscoveryStarted) {
81 mIsPrinterDiscoveryStarted = true;
82 try {
83 mPrintManager.startPrinterDiscovery(mObserver, priorityList, mUserId);
84 } catch (RemoteException re) {
85 Log.e(LOG_TAG, "Error starting printer discovery", re);
86 }
87 }
88 }
89
90 public final void stopPrinterDiscovery() {
91 if (isDestroyed()) {
92 Log.w(LOG_TAG, "Ignoring stop printers discovery - session destroyed");
Svetoslav Ganovd26d4892013-08-28 14:37:54 -070093 return;
Svetoslav Ganov44720af2013-08-20 16:32:53 -070094 }
95 if (mIsPrinterDiscoveryStarted) {
96 mIsPrinterDiscoveryStarted = false;
97 try {
98 mPrintManager.stopPrinterDiscovery(mObserver, mUserId);
99 } catch (RemoteException re) {
100 Log.e(LOG_TAG, "Error stopping printer discovery", re);
101 }
102 }
103 }
104
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700105 public final void startPrinterStateTracking(PrinterId printerId) {
Svetoslav Ganov44720af2013-08-20 16:32:53 -0700106 if (isDestroyed()) {
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700107 Log.w(LOG_TAG, "Ignoring start printer state tracking - session destroyed");
108 return;
Svetoslav Ganov44720af2013-08-20 16:32:53 -0700109 }
110 try {
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700111 mPrintManager.startPrinterStateTracking(printerId, mUserId);
Svetoslav Ganov44720af2013-08-20 16:32:53 -0700112 } catch (RemoteException re) {
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700113 Log.e(LOG_TAG, "Error starting printer state tracking", re);
114 }
115 }
116
117 public final void stopPrinterStateTracking(PrinterId printerId) {
118 if (isDestroyed()) {
119 Log.w(LOG_TAG, "Ignoring stop printer state tracking - session destroyed");
120 return;
121 }
122 try {
123 mPrintManager.stopPrinterStateTracking(printerId, mUserId);
124 } catch (RemoteException re) {
Svetoslava798c0a2014-05-15 10:47:19 -0700125 Log.e(LOG_TAG, "Error stopping printer state tracking", re);
Svetoslav Ganovd26d4892013-08-28 14:37:54 -0700126 }
127 }
128
129 public final void validatePrinters(List<PrinterId> printerIds) {
130 if (isDestroyed()) {
131 Log.w(LOG_TAG, "Ignoring validate printers - session destroyed");
132 return;
133 }
134 try {
135 mPrintManager.validatePrinters(printerIds, mUserId);
136 } catch (RemoteException re) {
137 Log.e(LOG_TAG, "Error validating printers", re);
Svetoslav Ganov44720af2013-08-20 16:32:53 -0700138 }
139 }
140
141 public final void destroy() {
142 if (isDestroyed()) {
143 Log.w(LOG_TAG, "Ignoring destroy - session destroyed");
144 }
145 destroyNoCheck();
146 }
147
148 public final List<PrinterInfo> getPrinters() {
149 if (isDestroyed()) {
150 Log.w(LOG_TAG, "Ignoring get printers - session destroyed");
151 return Collections.emptyList();
152 }
153 return new ArrayList<PrinterInfo>(mPrinters.values());
154 }
155
156 public final boolean isDestroyed() {
157 throwIfNotCalledOnMainThread();
158 return isDestroyedNoCheck();
159 }
160
161 public final boolean isPrinterDiscoveryStarted() {
162 throwIfNotCalledOnMainThread();
163 return mIsPrinterDiscoveryStarted;
164 }
165
166 public final void setOnPrintersChangeListener(OnPrintersChangeListener listener) {
167 throwIfNotCalledOnMainThread();
168 mListener = listener;
169 }
170
171 @Override
172 protected final void finalize() throws Throwable {
173 if (!isDestroyedNoCheck()) {
174 Log.e(LOG_TAG, "Destroying leaked printer discovery session");
175 destroyNoCheck();
176 }
177 super.finalize();
178 }
179
180 private boolean isDestroyedNoCheck() {
181 return (mObserver == null);
182 }
183
184 private void destroyNoCheck() {
185 stopPrinterDiscovery();
186 try {
187 mPrintManager.destroyPrinterDiscoverySession(mObserver, mUserId);
188 } catch (RemoteException re) {
189 Log.e(LOG_TAG, "Error destroying printer discovery session", re);
190 } finally {
191 mObserver = null;
192 mPrinters.clear();
193 }
194 }
195
Svetoslavc335eb42013-09-26 15:55:47 -0700196 private void handlePrintersAdded(List<PrinterInfo> addedPrinters) {
Svetoslav Ganov44720af2013-08-20 16:32:53 -0700197 if (isDestroyed()) {
198 return;
199 }
Svetoslavc335eb42013-09-26 15:55:47 -0700200
201 // No old printers - do not bother keeping their position.
202 if (mPrinters.isEmpty()) {
203 final int printerCount = addedPrinters.size();
204 for (int i = 0; i < printerCount; i++) {
205 PrinterInfo printer = addedPrinters.get(i);
206 mPrinters.put(printer.getId(), printer);
207 }
208 notifyOnPrintersChanged();
209 return;
210 }
211
212 // Add the printers to a map.
213 ArrayMap<PrinterId, PrinterInfo> addedPrintersMap =
214 new ArrayMap<PrinterId, PrinterInfo>();
215 final int printerCount = addedPrinters.size();
216 for (int i = 0; i < printerCount; i++) {
217 PrinterInfo printer = addedPrinters.get(i);
218 addedPrintersMap.put(printer.getId(), printer);
219 }
220
221 // Update printers we already have.
Svetoslav Ganovcfab2452013-09-28 12:09:23 -0700222 for (PrinterId oldPrinterId : mPrinters.keySet()) {
Svetoslavc335eb42013-09-26 15:55:47 -0700223 PrinterInfo updatedPrinter = addedPrintersMap.remove(oldPrinterId);
224 if (updatedPrinter != null) {
225 mPrinters.put(oldPrinterId, updatedPrinter);
Svetoslav Ganov44720af2013-08-20 16:32:53 -0700226 }
227 }
Svetoslavc335eb42013-09-26 15:55:47 -0700228
229 // Add the new printers, i.e. what is left.
230 mPrinters.putAll(addedPrintersMap);
231
232 // Announce the change.
233 notifyOnPrintersChanged();
Svetoslav Ganov44720af2013-08-20 16:32:53 -0700234 }
235
236 private void handlePrintersRemoved(List<PrinterId> printerIds) {
237 if (isDestroyed()) {
238 return;
239 }
240 boolean printersChanged = false;
241 final int removedPrinterIdCount = printerIds.size();
242 for (int i = 0; i < removedPrinterIdCount; i++) {
243 PrinterId removedPrinterId = printerIds.get(i);
244 if (mPrinters.remove(removedPrinterId) != null) {
245 printersChanged = true;
246 }
247 }
248 if (printersChanged) {
249 notifyOnPrintersChanged();
250 }
251 }
252
Svetoslav Ganov44720af2013-08-20 16:32:53 -0700253 private void notifyOnPrintersChanged() {
254 if (mListener != null) {
255 mListener.onPrintersChanged();
256 }
257 }
258
259 private static void throwIfNotCalledOnMainThread() {
260 if (!Looper.getMainLooper().isCurrentThread()) {
261 throw new IllegalAccessError("must be called from the main thread");
262 }
263 }
264
265 private final class SessionHandler extends Handler {
266
267 public SessionHandler(Looper looper) {
268 super(looper, null, false);
269 }
270
271 @Override
272 @SuppressWarnings("unchecked")
273 public void handleMessage(Message message) {
274 switch (message.what) {
275 case MSG_PRINTERS_ADDED: {
276 List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
277 handlePrintersAdded(printers);
278 } break;
279
280 case MSG_PRINTERS_REMOVED: {
281 List<PrinterId> printerIds = (List<PrinterId>) message.obj;
282 handlePrintersRemoved(printerIds);
283 } break;
Svetoslav Ganov44720af2013-08-20 16:32:53 -0700284 }
285 }
286 }
287
288 private static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
289
290 private final WeakReference<PrinterDiscoverySession> mWeakSession;
291
292 public PrinterDiscoveryObserver(PrinterDiscoverySession session) {
293 mWeakSession = new WeakReference<PrinterDiscoverySession>(session);
294 }
295
296 @Override
Svetoslav2fbd2a72013-09-16 17:53:51 -0700297 @SuppressWarnings("rawtypes")
298 public void onPrintersAdded(ParceledListSlice printers) {
Svetoslav Ganov44720af2013-08-20 16:32:53 -0700299 PrinterDiscoverySession session = mWeakSession.get();
300 if (session != null) {
301 session.mHandler.obtainMessage(MSG_PRINTERS_ADDED,
Svetoslav2fbd2a72013-09-16 17:53:51 -0700302 printers.getList()).sendToTarget();
Svetoslav Ganov44720af2013-08-20 16:32:53 -0700303 }
304 }
305
306 @Override
Svetoslav2fbd2a72013-09-16 17:53:51 -0700307 @SuppressWarnings("rawtypes")
308 public void onPrintersRemoved(ParceledListSlice printerIds) {
Svetoslav Ganov44720af2013-08-20 16:32:53 -0700309 PrinterDiscoverySession session = mWeakSession.get();
310 if (session != null) {
311 session.mHandler.obtainMessage(MSG_PRINTERS_REMOVED,
Svetoslav2fbd2a72013-09-16 17:53:51 -0700312 printerIds.getList()).sendToTarget();
Svetoslav Ganov44720af2013-08-20 16:32:53 -0700313 }
314 }
Svetoslav Ganov44720af2013-08-20 16:32:53 -0700315 }
316}