• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.print;
18 
19 import android.content.Context;
20 import android.content.pm.ParceledListSlice;
21 import android.os.Handler;
22 import android.os.Looper;
23 import android.os.Message;
24 import android.os.RemoteException;
25 import android.util.ArrayMap;
26 import android.util.Log;
27 
28 import java.lang.ref.WeakReference;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.LinkedHashMap;
32 import java.util.List;
33 
34 /**
35  * @hide
36  */
37 public 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;
43 
44     private final LinkedHashMap<PrinterId, PrinterInfo> mPrinters =
45             new LinkedHashMap<PrinterId, PrinterInfo>();
46 
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 {
onPrintersChanged()60         public void onPrintersChanged();
61     }
62 
PrinterDiscoverySession(IPrintManager printManager, Context context, int userId)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 
startPrinterDiscovery(List<PrinterId> priorityList)75     public final void startPrinterDiscovery(List<PrinterId> priorityList) {
76         if (isDestroyed()) {
77             Log.w(LOG_TAG, "Ignoring start printers discovery - session destroyed");
78             return;
79         }
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 
stopPrinterDiscovery()90     public final void stopPrinterDiscovery() {
91         if (isDestroyed()) {
92             Log.w(LOG_TAG, "Ignoring stop printers discovery - session destroyed");
93             return;
94         }
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 
startPrinterStateTracking(PrinterId printerId)105     public final void startPrinterStateTracking(PrinterId printerId) {
106         if (isDestroyed()) {
107             Log.w(LOG_TAG, "Ignoring start printer state tracking - session destroyed");
108             return;
109         }
110         try {
111             mPrintManager.startPrinterStateTracking(printerId, mUserId);
112         } catch (RemoteException re) {
113             Log.e(LOG_TAG, "Error starting printer state tracking", re);
114         }
115     }
116 
stopPrinterStateTracking(PrinterId printerId)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) {
125             Log.e(LOG_TAG, "Error stopping printer state tracking", re);
126         }
127     }
128 
validatePrinters(List<PrinterId> printerIds)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);
138         }
139     }
140 
destroy()141     public final void destroy() {
142         if (isDestroyed()) {
143             Log.w(LOG_TAG, "Ignoring destroy - session destroyed");
144         }
145         destroyNoCheck();
146     }
147 
getPrinters()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 
isDestroyed()156     public final boolean isDestroyed() {
157         throwIfNotCalledOnMainThread();
158         return isDestroyedNoCheck();
159     }
160 
isPrinterDiscoveryStarted()161     public final boolean isPrinterDiscoveryStarted() {
162         throwIfNotCalledOnMainThread();
163         return mIsPrinterDiscoveryStarted;
164     }
165 
setOnPrintersChangeListener(OnPrintersChangeListener listener)166     public final void setOnPrintersChangeListener(OnPrintersChangeListener listener) {
167         throwIfNotCalledOnMainThread();
168         mListener = listener;
169     }
170 
171     @Override
finalize()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 
isDestroyedNoCheck()180     private boolean isDestroyedNoCheck() {
181         return (mObserver == null);
182     }
183 
destroyNoCheck()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 
handlePrintersAdded(List<PrinterInfo> addedPrinters)196     private void handlePrintersAdded(List<PrinterInfo> addedPrinters) {
197         if (isDestroyed()) {
198             return;
199         }
200 
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.
222         for (PrinterId oldPrinterId : mPrinters.keySet()) {
223             PrinterInfo updatedPrinter = addedPrintersMap.remove(oldPrinterId);
224             if (updatedPrinter != null) {
225                 mPrinters.put(oldPrinterId, updatedPrinter);
226             }
227         }
228 
229         // Add the new printers, i.e. what is left.
230         mPrinters.putAll(addedPrintersMap);
231 
232         // Announce the change.
233         notifyOnPrintersChanged();
234     }
235 
handlePrintersRemoved(List<PrinterId> printerIds)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 
notifyOnPrintersChanged()253     private void notifyOnPrintersChanged() {
254         if (mListener != null) {
255             mListener.onPrintersChanged();
256         }
257     }
258 
throwIfNotCalledOnMainThread()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 
SessionHandler(Looper looper)267         public SessionHandler(Looper looper) {
268             super(looper, null, false);
269         }
270 
271         @Override
272         @SuppressWarnings("unchecked")
handleMessage(Message message)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;
284             }
285         }
286     }
287 
288     private static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
289 
290         private final WeakReference<PrinterDiscoverySession> mWeakSession;
291 
PrinterDiscoveryObserver(PrinterDiscoverySession session)292         public PrinterDiscoveryObserver(PrinterDiscoverySession session) {
293             mWeakSession = new WeakReference<PrinterDiscoverySession>(session);
294         }
295 
296         @Override
297         @SuppressWarnings("rawtypes")
onPrintersAdded(ParceledListSlice printers)298         public void onPrintersAdded(ParceledListSlice printers) {
299             PrinterDiscoverySession session = mWeakSession.get();
300             if (session != null) {
301                 session.mHandler.obtainMessage(MSG_PRINTERS_ADDED,
302                         printers.getList()).sendToTarget();
303             }
304         }
305 
306         @Override
307         @SuppressWarnings("rawtypes")
onPrintersRemoved(ParceledListSlice printerIds)308         public void onPrintersRemoved(ParceledListSlice printerIds) {
309             PrinterDiscoverySession session = mWeakSession.get();
310             if (session != null) {
311                 session.mHandler.obtainMessage(MSG_PRINTERS_REMOVED,
312                         printerIds.getList()).sendToTarget();
313             }
314         }
315     }
316 }
317