PrinterDiscoverySession.java revision d26d4898fcc9b78f4b66118895c375384098205e
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
17package android.print;
18
19import android.content.Context;
20import android.os.Handler;
21import android.os.Looper;
22import android.os.Message;
23import android.os.RemoteException;
24import android.util.ArrayMap;
25import android.util.Log;
26
27import java.lang.ref.WeakReference;
28import java.util.ArrayList;
29import java.util.Collections;
30import java.util.List;
31
32/**
33 * @hide
34 */
35public final class PrinterDiscoverySession {
36
37    private static final String LOG_TAG ="PrinterDiscoverySession";
38
39    private static final int MSG_PRINTERS_ADDED = 1;
40    private static final int MSG_PRINTERS_REMOVED = 2;
41    private static final int MSG_PRINTERS_UPDATED = 3;
42
43    private final ArrayMap<PrinterId, PrinterInfo> mPrinters =
44            new ArrayMap<PrinterId, PrinterInfo>();
45
46    private final IPrintManager mPrintManager;
47
48    private final int mUserId;
49
50    private final Handler mHandler;
51
52    private IPrinterDiscoveryObserver mObserver;
53
54    private OnPrintersChangeListener mListener;
55
56    private boolean mIsPrinterDiscoveryStarted;
57
58    public static interface OnPrintersChangeListener {
59        public void onPrintersChanged();
60    }
61
62    PrinterDiscoverySession(IPrintManager printManager, Context context, int userId) {
63        mPrintManager = printManager;
64        mUserId = userId;
65        mHandler = new SessionHandler(context.getMainLooper());
66        mObserver = new PrinterDiscoveryObserver(this);
67        try {
68            mPrintManager.createPrinterDiscoverySession(mObserver, mUserId);
69        } catch (RemoteException re) {
70            Log.e(LOG_TAG, "Error creating printer discovery session", re);
71        }
72    }
73
74    public final void startPrinterDisovery(List<PrinterId> priorityList) {
75        if (isDestroyed()) {
76            Log.w(LOG_TAG, "Ignoring start printers dsicovery - session destroyed");
77            return;
78        }
79        if (!mIsPrinterDiscoveryStarted) {
80            mIsPrinterDiscoveryStarted = true;
81            try {
82                mPrintManager.startPrinterDiscovery(mObserver, priorityList, mUserId);
83            } catch (RemoteException re) {
84                Log.e(LOG_TAG, "Error starting printer discovery", re);
85            }
86        }
87    }
88
89    public final void stopPrinterDiscovery() {
90        if (isDestroyed()) {
91            Log.w(LOG_TAG, "Ignoring stop printers discovery - session destroyed");
92            return;
93        }
94        if (mIsPrinterDiscoveryStarted) {
95            mIsPrinterDiscoveryStarted = false;
96            try {
97                mPrintManager.stopPrinterDiscovery(mObserver, mUserId);
98            } catch (RemoteException re) {
99                Log.e(LOG_TAG, "Error stopping printer discovery", re);
100            }
101        }
102    }
103
104    public final void startPrinterStateTracking(PrinterId printerId) {
105        if (isDestroyed()) {
106            Log.w(LOG_TAG, "Ignoring start printer state tracking - session destroyed");
107            return;
108        }
109        try {
110            mPrintManager.startPrinterStateTracking(printerId, mUserId);
111        } catch (RemoteException re) {
112            Log.e(LOG_TAG, "Error starting printer state tracking", re);
113        }
114    }
115
116    public final void stopPrinterStateTracking(PrinterId printerId) {
117        if (isDestroyed()) {
118            Log.w(LOG_TAG, "Ignoring stop printer state tracking - session destroyed");
119            return;
120        }
121        try {
122            mPrintManager.stopPrinterStateTracking(printerId, mUserId);
123        } catch (RemoteException re) {
124            Log.e(LOG_TAG, "Error stoping printer state tracking", re);
125        }
126    }
127
128    public final void validatePrinters(List<PrinterId> printerIds) {
129        if (isDestroyed()) {
130            Log.w(LOG_TAG, "Ignoring validate printers - session destroyed");
131            return;
132        }
133        try {
134            mPrintManager.validatePrinters(printerIds, mUserId);
135        } catch (RemoteException re) {
136            Log.e(LOG_TAG, "Error validating printers", re);
137        }
138    }
139
140    public final void destroy() {
141        if (isDestroyed()) {
142            Log.w(LOG_TAG, "Ignoring destroy - session destroyed");
143        }
144        destroyNoCheck();
145    }
146
147    public final List<PrinterInfo> getPrinters() {
148        if (isDestroyed()) {
149            Log.w(LOG_TAG, "Ignoring get printers - session destroyed");
150            return Collections.emptyList();
151        }
152        return new ArrayList<PrinterInfo>(mPrinters.values());
153    }
154
155    public final boolean isDestroyed() {
156        throwIfNotCalledOnMainThread();
157        return isDestroyedNoCheck();
158    }
159
160    public final boolean isPrinterDiscoveryStarted() {
161        throwIfNotCalledOnMainThread();
162        return mIsPrinterDiscoveryStarted;
163    }
164
165    public final void setOnPrintersChangeListener(OnPrintersChangeListener listener) {
166        throwIfNotCalledOnMainThread();
167        mListener = listener;
168    }
169
170    @Override
171    protected final void finalize() throws Throwable {
172        if (!isDestroyedNoCheck()) {
173            Log.e(LOG_TAG, "Destroying leaked printer discovery session");
174            destroyNoCheck();
175        }
176        super.finalize();
177    }
178
179    private boolean isDestroyedNoCheck() {
180        return (mObserver == null);
181    }
182
183    private void destroyNoCheck() {
184        stopPrinterDiscovery();
185        try {
186            mPrintManager.destroyPrinterDiscoverySession(mObserver, mUserId);
187        } catch (RemoteException re) {
188            Log.e(LOG_TAG, "Error destroying printer discovery session", re);
189        } finally {
190            mObserver = null;
191            mPrinters.clear();
192        }
193    }
194
195    private void handlePrintersAdded(List<PrinterInfo> printers) {
196        if (isDestroyed()) {
197            return;
198        }
199        boolean printersChanged = false;
200        final int addedPrinterCount = printers.size();
201        for (int i = 0; i < addedPrinterCount; i++) {
202            PrinterInfo addedPrinter = printers.get(i);
203            if (mPrinters.get(addedPrinter.getId()) == null) {
204                mPrinters.put(addedPrinter.getId(), addedPrinter);
205                printersChanged = true;
206            }
207        }
208        if (printersChanged) {
209            notifyOnPrintersChanged();
210        }
211    }
212
213    private void handlePrintersRemoved(List<PrinterId> printerIds) {
214        if (isDestroyed()) {
215            return;
216        }
217        boolean printersChanged = false;
218        final int removedPrinterIdCount = printerIds.size();
219        for (int i = 0; i < removedPrinterIdCount; i++) {
220            PrinterId removedPrinterId = printerIds.get(i);
221            if (mPrinters.remove(removedPrinterId) != null) {
222                printersChanged = true;
223            }
224        }
225        if (printersChanged) {
226            notifyOnPrintersChanged();
227        }
228    }
229
230    private void handlePrintersUpdated(List<PrinterInfo> printers) {
231        if (isDestroyed()) {
232            return;
233        }
234        boolean printersChanged = false;
235        final int updatedPrinterCount = printers.size();
236        for (int i = 0; i < updatedPrinterCount; i++) {
237            PrinterInfo updatedPrinter = printers.get(i);
238            PrinterInfo oldPrinter = mPrinters.get(updatedPrinter.getId());
239            if (oldPrinter != null && !oldPrinter.equals(updatedPrinter)) {
240                mPrinters.put(updatedPrinter.getId(), updatedPrinter);
241                printersChanged = true;
242            }
243        }
244        if (printersChanged) {
245            notifyOnPrintersChanged();
246        }
247    }
248
249    private void notifyOnPrintersChanged() {
250        if (mListener != null) {
251            mListener.onPrintersChanged();
252        }
253    }
254
255    private static void throwIfNotCalledOnMainThread() {
256        if (!Looper.getMainLooper().isCurrentThread()) {
257            throw new IllegalAccessError("must be called from the main thread");
258        }
259    }
260
261    private final class SessionHandler extends Handler {
262
263        public SessionHandler(Looper looper) {
264            super(looper, null, false);
265        }
266
267        @Override
268        @SuppressWarnings("unchecked")
269        public void handleMessage(Message message) {
270            switch (message.what) {
271                case MSG_PRINTERS_ADDED: {
272                    List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
273                    handlePrintersAdded(printers);
274                } break;
275
276                case MSG_PRINTERS_REMOVED: {
277                    List<PrinterId> printerIds = (List<PrinterId>) message.obj;
278                    handlePrintersRemoved(printerIds);
279                } break;
280
281                case MSG_PRINTERS_UPDATED: {
282                    List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
283                    handlePrintersUpdated(printers);
284                } break;
285            }
286        }
287    }
288
289    private static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
290
291        private final WeakReference<PrinterDiscoverySession> mWeakSession;
292
293        public PrinterDiscoveryObserver(PrinterDiscoverySession session) {
294            mWeakSession = new WeakReference<PrinterDiscoverySession>(session);
295        }
296
297        @Override
298        public void onPrintersAdded(List<PrinterInfo> printers) {
299            PrinterDiscoverySession session = mWeakSession.get();
300            if (session != null) {
301                session.mHandler.obtainMessage(MSG_PRINTERS_ADDED,
302                        printers).sendToTarget();
303            }
304        }
305
306        @Override
307        public void onPrintersRemoved(List<PrinterId> printerIds) {
308            PrinterDiscoverySession session = mWeakSession.get();
309            if (session != null) {
310                session.mHandler.obtainMessage(MSG_PRINTERS_REMOVED,
311                        printerIds).sendToTarget();
312            }
313        }
314
315        @Override
316        public void onPrintersUpdated(List<PrinterInfo> printers) {
317            PrinterDiscoverySession session = mWeakSession.get();
318            if (session != null) {
319                session.mHandler.obtainMessage(MSG_PRINTERS_UPDATED,
320                        printers).sendToTarget();
321            }
322        }
323    }
324}
325