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