PrinterDiscoverySession.java revision 2fbd2a7f070f246ddafd9de94efa9a98861e9136
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.content.pm.ParceledListSlice;
21import 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;
31import java.util.List;
32
33/**
34 * @hide
35 */
36public final class PrinterDiscoverySession {
37
38    private static final String LOG_TAG ="PrinterDiscoverySession";
39
40    private static final int MSG_PRINTERS_ADDED = 1;
41    private static final int MSG_PRINTERS_REMOVED = 2;
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            PrinterInfo oldPrinter = mPrinters.put(addedPrinter.getId(), addedPrinter);
204            if (oldPrinter == null || !oldPrinter.equals(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 notifyOnPrintersChanged() {
231        if (mListener != null) {
232            mListener.onPrintersChanged();
233        }
234    }
235
236    private static void throwIfNotCalledOnMainThread() {
237        if (!Looper.getMainLooper().isCurrentThread()) {
238            throw new IllegalAccessError("must be called from the main thread");
239        }
240    }
241
242    private final class SessionHandler extends Handler {
243
244        public SessionHandler(Looper looper) {
245            super(looper, null, false);
246        }
247
248        @Override
249        @SuppressWarnings("unchecked")
250        public void handleMessage(Message message) {
251            switch (message.what) {
252                case MSG_PRINTERS_ADDED: {
253                    List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
254                    handlePrintersAdded(printers);
255                } break;
256
257                case MSG_PRINTERS_REMOVED: {
258                    List<PrinterId> printerIds = (List<PrinterId>) message.obj;
259                    handlePrintersRemoved(printerIds);
260                } break;
261            }
262        }
263    }
264
265    private static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
266
267        private final WeakReference<PrinterDiscoverySession> mWeakSession;
268
269        public PrinterDiscoveryObserver(PrinterDiscoverySession session) {
270            mWeakSession = new WeakReference<PrinterDiscoverySession>(session);
271        }
272
273        @Override
274        @SuppressWarnings("rawtypes")
275        public void onPrintersAdded(ParceledListSlice printers) {
276            PrinterDiscoverySession session = mWeakSession.get();
277            if (session != null) {
278                session.mHandler.obtainMessage(MSG_PRINTERS_ADDED,
279                        printers.getList()).sendToTarget();
280            }
281        }
282
283        @Override
284        @SuppressWarnings("rawtypes")
285        public void onPrintersRemoved(ParceledListSlice printerIds) {
286            PrinterDiscoverySession session = mWeakSession.get();
287            if (session != null) {
288                session.mHandler.obtainMessage(MSG_PRINTERS_REMOVED,
289                        printerIds.getList()).sendToTarget();
290            }
291        }
292    }
293}
294