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