PrinterDiscoverySession.java revision 44720af55a8fdf991929983dad5d53c02851dd1e
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        }
78        if (!mIsPrinterDiscoveryStarted) {
79            mIsPrinterDiscoveryStarted = true;
80            try {
81                mPrintManager.startPrinterDiscovery(mObserver, priorityList, mUserId);
82            } catch (RemoteException re) {
83                Log.e(LOG_TAG, "Error starting printer discovery", re);
84            }
85        }
86    }
87
88    public final void stopPrinterDiscovery() {
89        if (isDestroyed()) {
90            Log.w(LOG_TAG, "Ignoring stop printers discovery - session destroyed");
91        }
92        if (mIsPrinterDiscoveryStarted) {
93            mIsPrinterDiscoveryStarted = false;
94            try {
95                mPrintManager.stopPrinterDiscovery(mObserver, mUserId);
96            } catch (RemoteException re) {
97                Log.e(LOG_TAG, "Error stopping printer discovery", re);
98            }
99        }
100    }
101
102    public final void requestPrinterUpdate(PrinterId printerId) {
103        if (isDestroyed()) {
104            Log.w(LOG_TAG, "Ignoring reqeust printer update - session destroyed");
105        }
106        try {
107            mPrintManager.requestPrinterUpdate(printerId, mUserId);
108        } catch (RemoteException re) {
109            Log.e(LOG_TAG, "Error requesting printer update", re);
110        }
111    }
112
113    public final void destroy() {
114        if (isDestroyed()) {
115            Log.w(LOG_TAG, "Ignoring destroy - session destroyed");
116        }
117        destroyNoCheck();
118    }
119
120    public final List<PrinterInfo> getPrinters() {
121        if (isDestroyed()) {
122            Log.w(LOG_TAG, "Ignoring get printers - session destroyed");
123            return Collections.emptyList();
124        }
125        return new ArrayList<PrinterInfo>(mPrinters.values());
126    }
127
128    public final boolean isDestroyed() {
129        throwIfNotCalledOnMainThread();
130        return isDestroyedNoCheck();
131    }
132
133    public final boolean isPrinterDiscoveryStarted() {
134        throwIfNotCalledOnMainThread();
135        return mIsPrinterDiscoveryStarted;
136    }
137
138    public final void setOnPrintersChangeListener(OnPrintersChangeListener listener) {
139        throwIfNotCalledOnMainThread();
140        mListener = listener;
141    }
142
143    @Override
144    protected final void finalize() throws Throwable {
145        if (!isDestroyedNoCheck()) {
146            Log.e(LOG_TAG, "Destroying leaked printer discovery session");
147            destroyNoCheck();
148        }
149        super.finalize();
150    }
151
152    private boolean isDestroyedNoCheck() {
153        return (mObserver == null);
154    }
155
156    private void destroyNoCheck() {
157        stopPrinterDiscovery();
158        try {
159            mPrintManager.destroyPrinterDiscoverySession(mObserver, mUserId);
160        } catch (RemoteException re) {
161            Log.e(LOG_TAG, "Error destroying printer discovery session", re);
162        } finally {
163            mObserver = null;
164            mPrinters.clear();
165        }
166    }
167
168    private void handlePrintersAdded(List<PrinterInfo> printers) {
169        if (isDestroyed()) {
170            return;
171        }
172        boolean printersChanged = false;
173        final int addedPrinterCount = printers.size();
174        for (int i = 0; i < addedPrinterCount; i++) {
175            PrinterInfo addedPrinter = printers.get(i);
176            if (mPrinters.get(addedPrinter.getId()) == null) {
177                mPrinters.put(addedPrinter.getId(), addedPrinter);
178                printersChanged = true;
179            }
180        }
181        if (printersChanged) {
182            notifyOnPrintersChanged();
183        }
184    }
185
186    private void handlePrintersRemoved(List<PrinterId> printerIds) {
187        if (isDestroyed()) {
188            return;
189        }
190        boolean printersChanged = false;
191        final int removedPrinterIdCount = printerIds.size();
192        for (int i = 0; i < removedPrinterIdCount; i++) {
193            PrinterId removedPrinterId = printerIds.get(i);
194            if (mPrinters.remove(removedPrinterId) != null) {
195                printersChanged = true;
196            }
197        }
198        if (printersChanged) {
199            notifyOnPrintersChanged();
200        }
201    }
202
203    private void handlePrintersUpdated(List<PrinterInfo> printers) {
204        if (isDestroyed()) {
205            return;
206        }
207        boolean printersChanged = false;
208        final int updatedPrinterCount = printers.size();
209        for (int i = 0; i < updatedPrinterCount; i++) {
210            PrinterInfo updatedPrinter = printers.get(i);
211            PrinterInfo oldPrinter = mPrinters.get(updatedPrinter.getId());
212            if (oldPrinter != null && !oldPrinter.equals(updatedPrinter)) {
213                mPrinters.put(updatedPrinter.getId(), updatedPrinter);
214                printersChanged = true;
215            }
216        }
217        if (printersChanged) {
218            notifyOnPrintersChanged();
219        }
220    }
221
222    private void notifyOnPrintersChanged() {
223        if (mListener != null) {
224            mListener.onPrintersChanged();
225        }
226    }
227
228    private static void throwIfNotCalledOnMainThread() {
229        if (!Looper.getMainLooper().isCurrentThread()) {
230            throw new IllegalAccessError("must be called from the main thread");
231        }
232    }
233
234    private final class SessionHandler extends Handler {
235
236        public SessionHandler(Looper looper) {
237            super(looper, null, false);
238        }
239
240        @Override
241        @SuppressWarnings("unchecked")
242        public void handleMessage(Message message) {
243            switch (message.what) {
244                case MSG_PRINTERS_ADDED: {
245                    List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
246                    handlePrintersAdded(printers);
247                } break;
248
249                case MSG_PRINTERS_REMOVED: {
250                    List<PrinterId> printerIds = (List<PrinterId>) message.obj;
251                    handlePrintersRemoved(printerIds);
252                } break;
253
254                case MSG_PRINTERS_UPDATED: {
255                    List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
256                    handlePrintersUpdated(printers);
257                } break;
258            }
259        }
260    }
261
262    private static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
263
264        private final WeakReference<PrinterDiscoverySession> mWeakSession;
265
266        public PrinterDiscoveryObserver(PrinterDiscoverySession session) {
267            mWeakSession = new WeakReference<PrinterDiscoverySession>(session);
268        }
269
270        @Override
271        public void onPrintersAdded(List<PrinterInfo> printers) {
272            PrinterDiscoverySession session = mWeakSession.get();
273            if (session != null) {
274                session.mHandler.obtainMessage(MSG_PRINTERS_ADDED,
275                        printers).sendToTarget();
276            }
277        }
278
279        @Override
280        public void onPrintersRemoved(List<PrinterId> printerIds) {
281            PrinterDiscoverySession session = mWeakSession.get();
282            if (session != null) {
283                session.mHandler.obtainMessage(MSG_PRINTERS_REMOVED,
284                        printerIds).sendToTarget();
285            }
286        }
287
288        @Override
289        public void onPrintersUpdated(List<PrinterInfo> printers) {
290            PrinterDiscoverySession session = mWeakSession.get();
291            if (session != null) {
292                session.mHandler.obtainMessage(MSG_PRINTERS_UPDATED,
293                        printers).sendToTarget();
294            }
295        }
296    }
297}
298