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