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 17 package com.android.server.print; 18 19 import android.app.PendingIntent; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentSender; 24 import android.content.pm.ApplicationInfo; 25 import android.content.pm.PackageManager; 26 import android.content.pm.ParceledListSlice; 27 import android.content.pm.ResolveInfo; 28 import android.content.pm.ServiceInfo; 29 import android.net.Uri; 30 import android.os.AsyncTask; 31 import android.os.Binder; 32 import android.os.Bundle; 33 import android.os.Handler; 34 import android.os.IBinder; 35 import android.os.IBinder.DeathRecipient; 36 import android.os.Looper; 37 import android.os.Message; 38 import android.os.RemoteCallbackList; 39 import android.os.RemoteException; 40 import android.os.UserHandle; 41 import android.print.IPrintDocumentAdapter; 42 import android.print.IPrintJobStateChangeListener; 43 import android.print.IPrinterDiscoveryObserver; 44 import android.print.PrintAttributes; 45 import android.print.PrintJobId; 46 import android.print.PrintJobInfo; 47 import android.print.PrintManager; 48 import android.print.PrinterId; 49 import android.print.PrinterInfo; 50 import android.printservice.PrintServiceInfo; 51 import android.provider.DocumentsContract; 52 import android.provider.Settings; 53 import android.text.TextUtils; 54 import android.text.TextUtils.SimpleStringSplitter; 55 import android.util.ArrayMap; 56 import android.util.ArraySet; 57 import android.util.Log; 58 import android.util.Slog; 59 import android.util.SparseArray; 60 61 import com.android.internal.R; 62 import com.android.internal.os.BackgroundThread; 63 import com.android.internal.os.SomeArgs; 64 import com.android.server.print.RemotePrintService.PrintServiceCallbacks; 65 import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks; 66 67 import java.io.FileDescriptor; 68 import java.io.PrintWriter; 69 import java.util.ArrayList; 70 import java.util.Collections; 71 import java.util.HashSet; 72 import java.util.Iterator; 73 import java.util.List; 74 import java.util.Map; 75 import java.util.Set; 76 77 /** 78 * Represents the print state for a user. 79 */ 80 final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { 81 82 private static final String LOG_TAG = "UserState"; 83 84 private static final boolean DEBUG = false; 85 86 private static final char COMPONENT_NAME_SEPARATOR = ':'; 87 88 private final SimpleStringSplitter mStringColonSplitter = 89 new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); 90 91 private final Intent mQueryIntent = 92 new Intent(android.printservice.PrintService.SERVICE_INTERFACE); 93 94 private final ArrayMap<ComponentName, RemotePrintService> mActiveServices = 95 new ArrayMap<ComponentName, RemotePrintService>(); 96 97 private final List<PrintServiceInfo> mInstalledServices = 98 new ArrayList<PrintServiceInfo>(); 99 100 private final Set<ComponentName> mEnabledServices = 101 new ArraySet<ComponentName>(); 102 103 private final PrintJobForAppCache mPrintJobForAppCache = 104 new PrintJobForAppCache(); 105 106 private final Object mLock; 107 108 private final Context mContext; 109 110 private final int mUserId; 111 112 private final RemotePrintSpooler mSpooler; 113 114 private final Handler mHandler; 115 116 private PrinterDiscoverySessionMediator mPrinterDiscoverySession; 117 118 private List<PrintJobStateChangeListenerRecord> mPrintJobStateChangeListenerRecords; 119 120 private boolean mDestroyed; 121 UserState(Context context, int userId, Object lock)122 public UserState(Context context, int userId, Object lock) { 123 mContext = context; 124 mUserId = userId; 125 mLock = lock; 126 mSpooler = new RemotePrintSpooler(context, userId, this); 127 mHandler = new UserStateHandler(context.getMainLooper()); 128 synchronized (mLock) { 129 enableSystemPrintServicesLocked(); 130 onConfigurationChangedLocked(); 131 } 132 } 133 134 @Override onPrintJobQueued(PrintJobInfo printJob)135 public void onPrintJobQueued(PrintJobInfo printJob) { 136 final RemotePrintService service; 137 synchronized (mLock) { 138 throwIfDestroyedLocked(); 139 ComponentName printServiceName = printJob.getPrinterId().getServiceName(); 140 service = mActiveServices.get(printServiceName); 141 } 142 if (service != null) { 143 service.onPrintJobQueued(printJob); 144 } else { 145 // The service for the job is no longer enabled, so just 146 // fail the job with the appropriate message. 147 mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED, 148 mContext.getString(R.string.reason_service_unavailable)); 149 } 150 } 151 152 @Override onAllPrintJobsForServiceHandled(ComponentName printService)153 public void onAllPrintJobsForServiceHandled(ComponentName printService) { 154 final RemotePrintService service; 155 synchronized (mLock) { 156 throwIfDestroyedLocked(); 157 service = mActiveServices.get(printService); 158 } 159 if (service != null) { 160 service.onAllPrintJobsHandled(); 161 } 162 } 163 removeObsoletePrintJobs()164 public void removeObsoletePrintJobs() { 165 mSpooler.removeObsoletePrintJobs(); 166 } 167 168 @SuppressWarnings("deprecation") print(String printJobName, IPrintDocumentAdapter adapter, PrintAttributes attributes, String packageName, int appId)169 public Bundle print(String printJobName, IPrintDocumentAdapter adapter, 170 PrintAttributes attributes, String packageName, int appId) { 171 // Create print job place holder. 172 final PrintJobInfo printJob = new PrintJobInfo(); 173 printJob.setId(new PrintJobId()); 174 printJob.setAppId(appId); 175 printJob.setLabel(printJobName); 176 printJob.setAttributes(attributes); 177 printJob.setState(PrintJobInfo.STATE_CREATED); 178 printJob.setCopies(1); 179 printJob.setCreationTime(System.currentTimeMillis()); 180 181 // Track this job so we can forget it when the creator dies. 182 if (!mPrintJobForAppCache.onPrintJobCreated(adapter.asBinder(), appId, 183 printJob)) { 184 // Not adding a print job means the client is dead - done. 185 return null; 186 } 187 188 // Spin the spooler to add the job and show the config UI. 189 new AsyncTask<Void, Void, Void>() { 190 @Override 191 protected Void doInBackground(Void... params) { 192 mSpooler.createPrintJob(printJob); 193 return null; 194 } 195 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); 196 197 final long identity = Binder.clearCallingIdentity(); 198 try { 199 Intent intent = new Intent(PrintManager.ACTION_PRINT_DIALOG); 200 intent.setData(Uri.fromParts("printjob", printJob.getId().flattenToString(), null)); 201 intent.putExtra(PrintManager.EXTRA_PRINT_DOCUMENT_ADAPTER, adapter.asBinder()); 202 intent.putExtra(PrintManager.EXTRA_PRINT_JOB, printJob); 203 intent.putExtra(DocumentsContract.EXTRA_PACKAGE_NAME, packageName); 204 205 IntentSender intentSender = PendingIntent.getActivityAsUser( 206 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT 207 | PendingIntent.FLAG_CANCEL_CURRENT, null, new UserHandle(mUserId)) 208 .getIntentSender(); 209 210 Bundle result = new Bundle(); 211 result.putParcelable(PrintManager.EXTRA_PRINT_JOB, printJob); 212 result.putParcelable(PrintManager.EXTRA_PRINT_DIALOG_INTENT, intentSender); 213 214 return result; 215 } finally { 216 Binder.restoreCallingIdentity(identity); 217 } 218 } 219 getPrintJobInfos(int appId)220 public List<PrintJobInfo> getPrintJobInfos(int appId) { 221 List<PrintJobInfo> cachedPrintJobs = mPrintJobForAppCache.getPrintJobs(appId); 222 // Note that the print spooler is not storing print jobs that 223 // are in a terminal state as it is non-trivial to properly update 224 // the spooler state for when to forget print jobs in terminal state. 225 // Therefore, we fuse the cached print jobs for running apps (some 226 // jobs are in a terminal state) with the ones that the print 227 // spooler knows about (some jobs are being processed). 228 ArrayMap<PrintJobId, PrintJobInfo> result = 229 new ArrayMap<PrintJobId, PrintJobInfo>(); 230 231 // Add the cached print jobs for running apps. 232 final int cachedPrintJobCount = cachedPrintJobs.size(); 233 for (int i = 0; i < cachedPrintJobCount; i++) { 234 PrintJobInfo cachedPrintJob = cachedPrintJobs.get(i); 235 result.put(cachedPrintJob.getId(), cachedPrintJob); 236 // Strip out the tag and the advanced print options. 237 // They are visible only to print services. 238 cachedPrintJob.setTag(null); 239 cachedPrintJob.setAdvancedOptions(null); 240 } 241 242 // Add everything else the spooler knows about. 243 List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(null, 244 PrintJobInfo.STATE_ANY, appId); 245 if (printJobs != null) { 246 final int printJobCount = printJobs.size(); 247 for (int i = 0; i < printJobCount; i++) { 248 PrintJobInfo printJob = printJobs.get(i); 249 result.put(printJob.getId(), printJob); 250 // Strip out the tag and the advanced print options. 251 // They are visible only to print services. 252 printJob.setTag(null); 253 printJob.setAdvancedOptions(null); 254 } 255 } 256 257 return new ArrayList<PrintJobInfo>(result.values()); 258 } 259 getPrintJobInfo(PrintJobId printJobId, int appId)260 public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) { 261 PrintJobInfo printJob = mPrintJobForAppCache.getPrintJob(printJobId, appId); 262 if (printJob == null) { 263 printJob = mSpooler.getPrintJobInfo(printJobId, appId); 264 } 265 if (printJob != null) { 266 // Strip out the tag and the advanced print options. 267 // They are visible only to print services. 268 printJob.setTag(null); 269 printJob.setAdvancedOptions(null); 270 } 271 return printJob; 272 } 273 cancelPrintJob(PrintJobId printJobId, int appId)274 public void cancelPrintJob(PrintJobId printJobId, int appId) { 275 PrintJobInfo printJobInfo = mSpooler.getPrintJobInfo(printJobId, appId); 276 if (printJobInfo == null) { 277 return; 278 } 279 280 // Take a note that we are trying to cancel the job. 281 mSpooler.setPrintJobCancelling(printJobId, true); 282 283 if (printJobInfo.getState() != PrintJobInfo.STATE_FAILED) { 284 ComponentName printServiceName = printJobInfo.getPrinterId().getServiceName(); 285 RemotePrintService printService = null; 286 synchronized (mLock) { 287 printService = mActiveServices.get(printServiceName); 288 } 289 if (printService == null) { 290 return; 291 } 292 printService.onRequestCancelPrintJob(printJobInfo); 293 } else { 294 // If the print job is failed we do not need cooperation 295 // from the print service. 296 mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_CANCELED, null); 297 } 298 } 299 restartPrintJob(PrintJobId printJobId, int appId)300 public void restartPrintJob(PrintJobId printJobId, int appId) { 301 PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, appId); 302 if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) { 303 return; 304 } 305 mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_QUEUED, null); 306 } 307 getEnabledPrintServices()308 public List<PrintServiceInfo> getEnabledPrintServices() { 309 synchronized (mLock) { 310 List<PrintServiceInfo> enabledServices = null; 311 final int installedServiceCount = mInstalledServices.size(); 312 for (int i = 0; i < installedServiceCount; i++) { 313 PrintServiceInfo installedService = mInstalledServices.get(i); 314 ComponentName componentName = new ComponentName( 315 installedService.getResolveInfo().serviceInfo.packageName, 316 installedService.getResolveInfo().serviceInfo.name); 317 if (mActiveServices.containsKey(componentName)) { 318 if (enabledServices == null) { 319 enabledServices = new ArrayList<PrintServiceInfo>(); 320 } 321 enabledServices.add(installedService); 322 } 323 } 324 return enabledServices; 325 } 326 } 327 getInstalledPrintServices()328 public List<PrintServiceInfo> getInstalledPrintServices() { 329 synchronized (mLock) { 330 return mInstalledServices; 331 } 332 } 333 createPrinterDiscoverySession(IPrinterDiscoveryObserver observer)334 public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer) { 335 synchronized (mLock) { 336 throwIfDestroyedLocked(); 337 if (mActiveServices.isEmpty()) { 338 return; 339 } 340 if (mPrinterDiscoverySession == null) { 341 // If we do not have a session, tell all service to create one. 342 mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) { 343 @Override 344 public void onDestroyed() { 345 mPrinterDiscoverySession = null; 346 } 347 }; 348 // Add the observer to the brand new session. 349 mPrinterDiscoverySession.addObserverLocked(observer); 350 } else { 351 // If services have created session, just add the observer. 352 mPrinterDiscoverySession.addObserverLocked(observer); 353 } 354 } 355 } 356 destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer)357 public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer) { 358 synchronized (mLock) { 359 // Already destroyed - nothing to do. 360 if (mPrinterDiscoverySession == null) { 361 return; 362 } 363 // Remove this observer. 364 mPrinterDiscoverySession.removeObserverLocked(observer); 365 } 366 } 367 startPrinterDiscovery(IPrinterDiscoveryObserver observer, List<PrinterId> printerIds)368 public void startPrinterDiscovery(IPrinterDiscoveryObserver observer, 369 List<PrinterId> printerIds) { 370 synchronized (mLock) { 371 throwIfDestroyedLocked(); 372 // No services - nothing to do. 373 if (mActiveServices.isEmpty()) { 374 return; 375 } 376 // No session - nothing to do. 377 if (mPrinterDiscoverySession == null) { 378 return; 379 } 380 // Kick of discovery. 381 mPrinterDiscoverySession.startPrinterDiscoveryLocked(observer, 382 printerIds); 383 } 384 } 385 stopPrinterDiscovery(IPrinterDiscoveryObserver observer)386 public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer) { 387 synchronized (mLock) { 388 throwIfDestroyedLocked(); 389 // No services - nothing to do. 390 if (mActiveServices.isEmpty()) { 391 return; 392 } 393 // No session - nothing to do. 394 if (mPrinterDiscoverySession == null) { 395 return; 396 } 397 // Kick of discovery. 398 mPrinterDiscoverySession.stopPrinterDiscoveryLocked(observer); 399 } 400 } 401 validatePrinters(List<PrinterId> printerIds)402 public void validatePrinters(List<PrinterId> printerIds) { 403 synchronized (mLock) { 404 throwIfDestroyedLocked(); 405 // No services - nothing to do. 406 if (mActiveServices.isEmpty()) { 407 return; 408 } 409 // No session - nothing to do. 410 if (mPrinterDiscoverySession == null) { 411 return; 412 } 413 // Request an updated. 414 mPrinterDiscoverySession.validatePrintersLocked(printerIds); 415 } 416 } 417 startPrinterStateTracking(PrinterId printerId)418 public void startPrinterStateTracking(PrinterId printerId) { 419 synchronized (mLock) { 420 throwIfDestroyedLocked(); 421 // No services - nothing to do. 422 if (mActiveServices.isEmpty()) { 423 return; 424 } 425 // No session - nothing to do. 426 if (mPrinterDiscoverySession == null) { 427 return; 428 } 429 // Request start tracking the printer. 430 mPrinterDiscoverySession.startPrinterStateTrackingLocked(printerId); 431 } 432 } 433 stopPrinterStateTracking(PrinterId printerId)434 public void stopPrinterStateTracking(PrinterId printerId) { 435 synchronized (mLock) { 436 throwIfDestroyedLocked(); 437 // No services - nothing to do. 438 if (mActiveServices.isEmpty()) { 439 return; 440 } 441 // No session - nothing to do. 442 if (mPrinterDiscoverySession == null) { 443 return; 444 } 445 // Request stop tracking the printer. 446 mPrinterDiscoverySession.stopPrinterStateTrackingLocked(printerId); 447 } 448 } 449 addPrintJobStateChangeListener(IPrintJobStateChangeListener listener, int appId)450 public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener, 451 int appId) throws RemoteException { 452 synchronized (mLock) { 453 throwIfDestroyedLocked(); 454 if (mPrintJobStateChangeListenerRecords == null) { 455 mPrintJobStateChangeListenerRecords = 456 new ArrayList<PrintJobStateChangeListenerRecord>(); 457 } 458 mPrintJobStateChangeListenerRecords.add( 459 new PrintJobStateChangeListenerRecord(listener, appId) { 460 @Override 461 public void onBinderDied() { 462 mPrintJobStateChangeListenerRecords.remove(this); 463 } 464 }); 465 } 466 } 467 removePrintJobStateChangeListener(IPrintJobStateChangeListener listener)468 public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener) { 469 synchronized (mLock) { 470 throwIfDestroyedLocked(); 471 if (mPrintJobStateChangeListenerRecords == null) { 472 return; 473 } 474 final int recordCount = mPrintJobStateChangeListenerRecords.size(); 475 for (int i = 0; i < recordCount; i++) { 476 PrintJobStateChangeListenerRecord record = 477 mPrintJobStateChangeListenerRecords.get(i); 478 if (record.listener.asBinder().equals(listener.asBinder())) { 479 mPrintJobStateChangeListenerRecords.remove(i); 480 break; 481 } 482 } 483 if (mPrintJobStateChangeListenerRecords.isEmpty()) { 484 mPrintJobStateChangeListenerRecords = null; 485 } 486 } 487 } 488 489 @Override onPrintJobStateChanged(PrintJobInfo printJob)490 public void onPrintJobStateChanged(PrintJobInfo printJob) { 491 mPrintJobForAppCache.onPrintJobStateChanged(printJob); 492 mHandler.obtainMessage(UserStateHandler.MSG_DISPATCH_PRINT_JOB_STATE_CHANGED, 493 printJob.getAppId(), 0, printJob.getId()).sendToTarget(); 494 } 495 496 @Override onPrintersAdded(List<PrinterInfo> printers)497 public void onPrintersAdded(List<PrinterInfo> printers) { 498 synchronized (mLock) { 499 throwIfDestroyedLocked(); 500 // No services - nothing to do. 501 if (mActiveServices.isEmpty()) { 502 return; 503 } 504 // No session - nothing to do. 505 if (mPrinterDiscoverySession == null) { 506 return; 507 } 508 mPrinterDiscoverySession.onPrintersAddedLocked(printers); 509 } 510 } 511 512 @Override onPrintersRemoved(List<PrinterId> printerIds)513 public void onPrintersRemoved(List<PrinterId> printerIds) { 514 synchronized (mLock) { 515 throwIfDestroyedLocked(); 516 // No services - nothing to do. 517 if (mActiveServices.isEmpty()) { 518 return; 519 } 520 // No session - nothing to do. 521 if (mPrinterDiscoverySession == null) { 522 return; 523 } 524 mPrinterDiscoverySession.onPrintersRemovedLocked(printerIds); 525 } 526 } 527 528 @Override onServiceDied(RemotePrintService service)529 public void onServiceDied(RemotePrintService service) { 530 synchronized (mLock) { 531 throwIfDestroyedLocked(); 532 // No services - nothing to do. 533 if (mActiveServices.isEmpty()) { 534 return; 535 } 536 // Fail all print jobs. 537 failActivePrintJobsForService(service.getComponentName()); 538 service.onAllPrintJobsHandled(); 539 // No session - nothing to do. 540 if (mPrinterDiscoverySession == null) { 541 return; 542 } 543 mPrinterDiscoverySession.onServiceDiedLocked(service); 544 } 545 } 546 updateIfNeededLocked()547 public void updateIfNeededLocked() { 548 throwIfDestroyedLocked(); 549 if (readConfigurationLocked()) { 550 onConfigurationChangedLocked(); 551 } 552 } 553 getEnabledServices()554 public Set<ComponentName> getEnabledServices() { 555 synchronized(mLock) { 556 throwIfDestroyedLocked(); 557 return mEnabledServices; 558 } 559 } 560 destroyLocked()561 public void destroyLocked() { 562 throwIfDestroyedLocked(); 563 mSpooler.destroy(); 564 for (RemotePrintService service : mActiveServices.values()) { 565 service.destroy(); 566 } 567 mActiveServices.clear(); 568 mInstalledServices.clear(); 569 mEnabledServices.clear(); 570 if (mPrinterDiscoverySession != null) { 571 mPrinterDiscoverySession.destroyLocked(); 572 mPrinterDiscoverySession = null; 573 } 574 mDestroyed = true; 575 } 576 dump(FileDescriptor fd, PrintWriter pw, String prefix)577 public void dump(FileDescriptor fd, PrintWriter pw, String prefix) { 578 pw.append(prefix).append("user state ").append(String.valueOf(mUserId)).append(":"); 579 pw.println(); 580 581 String tab = " "; 582 583 pw.append(prefix).append(tab).append("installed services:").println(); 584 final int installedServiceCount = mInstalledServices.size(); 585 for (int i = 0; i < installedServiceCount; i++) { 586 PrintServiceInfo installedService = mInstalledServices.get(i); 587 String installedServicePrefix = prefix + tab + tab; 588 pw.append(installedServicePrefix).append("service:").println(); 589 ResolveInfo resolveInfo = installedService.getResolveInfo(); 590 ComponentName componentName = new ComponentName( 591 resolveInfo.serviceInfo.packageName, 592 resolveInfo.serviceInfo.name); 593 pw.append(installedServicePrefix).append(tab).append("componentName=") 594 .append(componentName.flattenToString()).println(); 595 pw.append(installedServicePrefix).append(tab).append("settingsActivity=") 596 .append(installedService.getSettingsActivityName()).println(); 597 pw.append(installedServicePrefix).append(tab).append("addPrintersActivity=") 598 .append(installedService.getAddPrintersActivityName()).println(); 599 pw.append(installedServicePrefix).append(tab).append("avancedOptionsActivity=") 600 .append(installedService.getAdvancedOptionsActivityName()).println(); 601 } 602 603 pw.append(prefix).append(tab).append("enabled services:").println(); 604 for (ComponentName enabledService : mEnabledServices) { 605 String enabledServicePrefix = prefix + tab + tab; 606 pw.append(enabledServicePrefix).append("service:").println(); 607 pw.append(enabledServicePrefix).append(tab).append("componentName=") 608 .append(enabledService.flattenToString()); 609 pw.println(); 610 } 611 612 pw.append(prefix).append(tab).append("active services:").println(); 613 final int activeServiceCount = mActiveServices.size(); 614 for (int i = 0; i < activeServiceCount; i++) { 615 RemotePrintService activeService = mActiveServices.valueAt(i); 616 activeService.dump(pw, prefix + tab + tab); 617 pw.println(); 618 } 619 620 pw.append(prefix).append(tab).append("cached print jobs:").println(); 621 mPrintJobForAppCache.dump(pw, prefix + tab + tab); 622 623 pw.append(prefix).append(tab).append("discovery mediator:").println(); 624 if (mPrinterDiscoverySession != null) { 625 mPrinterDiscoverySession.dump(pw, prefix + tab + tab); 626 } 627 628 pw.append(prefix).append(tab).append("print spooler:").println(); 629 mSpooler.dump(fd, pw, prefix + tab + tab); 630 pw.println(); 631 } 632 readConfigurationLocked()633 private boolean readConfigurationLocked() { 634 boolean somethingChanged = false; 635 somethingChanged |= readInstalledPrintServicesLocked(); 636 somethingChanged |= readEnabledPrintServicesLocked(); 637 return somethingChanged; 638 } 639 readInstalledPrintServicesLocked()640 private boolean readInstalledPrintServicesLocked() { 641 Set<PrintServiceInfo> tempPrintServices = new HashSet<PrintServiceInfo>(); 642 643 List<ResolveInfo> installedServices = mContext.getPackageManager() 644 .queryIntentServicesAsUser(mQueryIntent, PackageManager.GET_SERVICES 645 | PackageManager.GET_META_DATA, mUserId); 646 647 final int installedCount = installedServices.size(); 648 for (int i = 0, count = installedCount; i < count; i++) { 649 ResolveInfo installedService = installedServices.get(i); 650 if (!android.Manifest.permission.BIND_PRINT_SERVICE.equals( 651 installedService.serviceInfo.permission)) { 652 ComponentName serviceName = new ComponentName( 653 installedService.serviceInfo.packageName, 654 installedService.serviceInfo.name); 655 Slog.w(LOG_TAG, "Skipping print service " 656 + serviceName.flattenToShortString() 657 + " since it does not require permission " 658 + android.Manifest.permission.BIND_PRINT_SERVICE); 659 continue; 660 } 661 tempPrintServices.add(PrintServiceInfo.create(installedService, mContext)); 662 } 663 664 boolean someServiceChanged = false; 665 666 if (tempPrintServices.size() != mInstalledServices.size()) { 667 someServiceChanged = true; 668 } else { 669 for (PrintServiceInfo newService: tempPrintServices) { 670 final int oldServiceIndex = mInstalledServices.indexOf(newService); 671 if (oldServiceIndex < 0) { 672 someServiceChanged = true; 673 break; 674 } 675 // PrintServiceInfo#equals compares only the id not all members, 676 // so we are also comparing the members coming from meta-data. 677 PrintServiceInfo oldService = mInstalledServices.get(oldServiceIndex); 678 if (!TextUtils.equals(oldService.getAddPrintersActivityName(), 679 newService.getAddPrintersActivityName()) 680 || !TextUtils.equals(oldService.getAdvancedOptionsActivityName(), 681 newService.getAdvancedOptionsActivityName()) 682 || !TextUtils.equals(oldService.getSettingsActivityName(), 683 newService.getSettingsActivityName())) { 684 someServiceChanged = true; 685 break; 686 } 687 } 688 } 689 690 if (someServiceChanged) { 691 mInstalledServices.clear(); 692 mInstalledServices.addAll(tempPrintServices); 693 return true; 694 } 695 696 return false; 697 } 698 readEnabledPrintServicesLocked()699 private boolean readEnabledPrintServicesLocked() { 700 Set<ComponentName> tempEnabledServiceNameSet = new HashSet<ComponentName>(); 701 readPrintServicesFromSettingLocked(Settings.Secure.ENABLED_PRINT_SERVICES, 702 tempEnabledServiceNameSet); 703 if (!tempEnabledServiceNameSet.equals(mEnabledServices)) { 704 mEnabledServices.clear(); 705 mEnabledServices.addAll(tempEnabledServiceNameSet); 706 return true; 707 } 708 return false; 709 } 710 readPrintServicesFromSettingLocked(String setting, Set<ComponentName> outServiceNames)711 private void readPrintServicesFromSettingLocked(String setting, 712 Set<ComponentName> outServiceNames) { 713 String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), 714 setting, mUserId); 715 if (!TextUtils.isEmpty(settingValue)) { 716 TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; 717 splitter.setString(settingValue); 718 while (splitter.hasNext()) { 719 String string = splitter.next(); 720 if (TextUtils.isEmpty(string)) { 721 continue; 722 } 723 ComponentName componentName = ComponentName.unflattenFromString(string); 724 if (componentName != null) { 725 outServiceNames.add(componentName); 726 } 727 } 728 } 729 } 730 enableSystemPrintServicesLocked()731 private void enableSystemPrintServicesLocked() { 732 // Load enabled and installed services. 733 readEnabledPrintServicesLocked(); 734 readInstalledPrintServicesLocked(); 735 736 // Load the system services once enabled on first boot. 737 Set<ComponentName> enabledOnFirstBoot = new HashSet<ComponentName>(); 738 readPrintServicesFromSettingLocked( 739 Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES, 740 enabledOnFirstBoot); 741 742 StringBuilder builder = new StringBuilder(); 743 744 final int serviceCount = mInstalledServices.size(); 745 for (int i = 0; i < serviceCount; i++) { 746 ServiceInfo serviceInfo = mInstalledServices.get(i).getResolveInfo().serviceInfo; 747 // Enable system print services if we never did that and are not enabled. 748 if ((serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 749 ComponentName serviceName = new ComponentName( 750 serviceInfo.packageName, serviceInfo.name); 751 if (!mEnabledServices.contains(serviceName) 752 && !enabledOnFirstBoot.contains(serviceName)) { 753 if (builder.length() > 0) { 754 builder.append(":"); 755 } 756 builder.append(serviceName.flattenToString()); 757 } 758 } 759 } 760 761 // Nothing to be enabled - done. 762 if (builder.length() <= 0) { 763 return; 764 } 765 766 String servicesToEnable = builder.toString(); 767 768 // Update the enabled services setting. 769 String enabledServices = Settings.Secure.getStringForUser( 770 mContext.getContentResolver(), Settings.Secure.ENABLED_PRINT_SERVICES, mUserId); 771 if (TextUtils.isEmpty(enabledServices)) { 772 enabledServices = servicesToEnable; 773 } else { 774 enabledServices = enabledServices + ":" + servicesToEnable; 775 } 776 Settings.Secure.putStringForUser(mContext.getContentResolver(), 777 Settings.Secure.ENABLED_PRINT_SERVICES, enabledServices, mUserId); 778 779 // Update the enabled on first boot services setting. 780 String enabledOnFirstBootServices = Settings.Secure.getStringForUser( 781 mContext.getContentResolver(), 782 Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES, mUserId); 783 if (TextUtils.isEmpty(enabledOnFirstBootServices)) { 784 enabledOnFirstBootServices = servicesToEnable; 785 } else { 786 enabledOnFirstBootServices = enabledOnFirstBootServices + ":" + enabledServices; 787 } 788 Settings.Secure.putStringForUser(mContext.getContentResolver(), 789 Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES, 790 enabledOnFirstBootServices, mUserId); 791 } 792 onConfigurationChangedLocked()793 private void onConfigurationChangedLocked() { 794 Set<ComponentName> installedComponents = new ArraySet<ComponentName>(); 795 796 final int installedCount = mInstalledServices.size(); 797 for (int i = 0; i < installedCount; i++) { 798 ResolveInfo resolveInfo = mInstalledServices.get(i).getResolveInfo(); 799 ComponentName serviceName = new ComponentName(resolveInfo.serviceInfo.packageName, 800 resolveInfo.serviceInfo.name); 801 802 installedComponents.add(serviceName); 803 804 if (mEnabledServices.contains(serviceName)) { 805 if (!mActiveServices.containsKey(serviceName)) { 806 RemotePrintService service = new RemotePrintService( 807 mContext, serviceName, mUserId, mSpooler, this); 808 addServiceLocked(service); 809 } 810 } else { 811 RemotePrintService service = mActiveServices.remove(serviceName); 812 if (service != null) { 813 removeServiceLocked(service); 814 } 815 } 816 } 817 818 Iterator<Map.Entry<ComponentName, RemotePrintService>> iterator = 819 mActiveServices.entrySet().iterator(); 820 while (iterator.hasNext()) { 821 Map.Entry<ComponentName, RemotePrintService> entry = iterator.next(); 822 ComponentName serviceName = entry.getKey(); 823 RemotePrintService service = entry.getValue(); 824 if (!installedComponents.contains(serviceName)) { 825 removeServiceLocked(service); 826 iterator.remove(); 827 } 828 } 829 } 830 addServiceLocked(RemotePrintService service)831 private void addServiceLocked(RemotePrintService service) { 832 mActiveServices.put(service.getComponentName(), service); 833 if (mPrinterDiscoverySession != null) { 834 mPrinterDiscoverySession.onServiceAddedLocked(service); 835 } 836 } 837 removeServiceLocked(RemotePrintService service)838 private void removeServiceLocked(RemotePrintService service) { 839 // Fail all print jobs. 840 failActivePrintJobsForService(service.getComponentName()); 841 // If discovery is in progress, tear down the service. 842 if (mPrinterDiscoverySession != null) { 843 mPrinterDiscoverySession.onServiceRemovedLocked(service); 844 } else { 845 // Otherwise, just destroy it. 846 service.destroy(); 847 } 848 } 849 failActivePrintJobsForService(final ComponentName serviceName)850 private void failActivePrintJobsForService(final ComponentName serviceName) { 851 // Makes sure all active print jobs are failed since the service 852 // just died. Do this off the main thread since we do to allow 853 // calls into the spooler on the main thread. 854 if (Looper.getMainLooper().isCurrentThread()) { 855 BackgroundThread.getHandler().post(new Runnable() { 856 @Override 857 public void run() { 858 failScheduledPrintJobsForServiceInternal(serviceName); 859 } 860 }); 861 } else { 862 failScheduledPrintJobsForServiceInternal(serviceName); 863 } 864 } 865 failScheduledPrintJobsForServiceInternal(ComponentName serviceName)866 private void failScheduledPrintJobsForServiceInternal(ComponentName serviceName) { 867 List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(serviceName, 868 PrintJobInfo.STATE_ANY_SCHEDULED, PrintManager.APP_ID_ANY); 869 if (printJobs == null) { 870 return; 871 } 872 final long identity = Binder.clearCallingIdentity(); 873 try { 874 final int printJobCount = printJobs.size(); 875 for (int i = 0; i < printJobCount; i++) { 876 PrintJobInfo printJob = printJobs.get(i); 877 mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED, 878 mContext.getString(R.string.reason_service_unavailable)); 879 } 880 } finally { 881 Binder.restoreCallingIdentity(identity); 882 } 883 } 884 throwIfDestroyedLocked()885 private void throwIfDestroyedLocked() { 886 if (mDestroyed) { 887 throw new IllegalStateException("Cannot interact with a destroyed instance."); 888 } 889 } 890 handleDispatchPrintJobStateChanged(PrintJobId printJobId, int appId)891 private void handleDispatchPrintJobStateChanged(PrintJobId printJobId, int appId) { 892 final List<PrintJobStateChangeListenerRecord> records; 893 synchronized (mLock) { 894 if (mPrintJobStateChangeListenerRecords == null) { 895 return; 896 } 897 records = new ArrayList<PrintJobStateChangeListenerRecord>( 898 mPrintJobStateChangeListenerRecords); 899 } 900 final int recordCount = records.size(); 901 for (int i = 0; i < recordCount; i++) { 902 PrintJobStateChangeListenerRecord record = records.get(i); 903 if (record.appId == PrintManager.APP_ID_ANY 904 || record.appId == appId) 905 try { 906 record.listener.onPrintJobStateChanged(printJobId); 907 } catch (RemoteException re) { 908 Log.e(LOG_TAG, "Error notifying for print job state change", re); 909 } 910 } 911 } 912 913 private final class UserStateHandler extends Handler { 914 public static final int MSG_DISPATCH_PRINT_JOB_STATE_CHANGED = 1; 915 UserStateHandler(Looper looper)916 public UserStateHandler(Looper looper) { 917 super(looper, null, false); 918 } 919 920 @Override handleMessage(Message message)921 public void handleMessage(Message message) { 922 if (message.what == MSG_DISPATCH_PRINT_JOB_STATE_CHANGED) { 923 PrintJobId printJobId = (PrintJobId) message.obj; 924 final int appId = message.arg1; 925 handleDispatchPrintJobStateChanged(printJobId, appId); 926 } 927 } 928 } 929 930 private abstract class PrintJobStateChangeListenerRecord implements DeathRecipient { 931 final IPrintJobStateChangeListener listener; 932 final int appId; 933 PrintJobStateChangeListenerRecord(IPrintJobStateChangeListener listener, int appId)934 public PrintJobStateChangeListenerRecord(IPrintJobStateChangeListener listener, 935 int appId) throws RemoteException { 936 this.listener = listener; 937 this.appId = appId; 938 listener.asBinder().linkToDeath(this, 0); 939 } 940 941 @Override binderDied()942 public void binderDied() { 943 listener.asBinder().unlinkToDeath(this, 0); 944 onBinderDied(); 945 } 946 onBinderDied()947 public abstract void onBinderDied(); 948 } 949 950 private class PrinterDiscoverySessionMediator { 951 private final ArrayMap<PrinterId, PrinterInfo> mPrinters = 952 new ArrayMap<PrinterId, PrinterInfo>(); 953 954 private final RemoteCallbackList<IPrinterDiscoveryObserver> mDiscoveryObservers = 955 new RemoteCallbackList<IPrinterDiscoveryObserver>() { 956 @Override 957 public void onCallbackDied(IPrinterDiscoveryObserver observer) { 958 synchronized (mLock) { 959 stopPrinterDiscoveryLocked(observer); 960 removeObserverLocked(observer); 961 } 962 } 963 }; 964 965 private final List<IBinder> mStartedPrinterDiscoveryTokens = new ArrayList<IBinder>(); 966 967 private final List<PrinterId> mStateTrackedPrinters = new ArrayList<PrinterId>(); 968 969 private final Handler mHandler; 970 971 private boolean mIsDestroyed; 972 PrinterDiscoverySessionMediator(Context context)973 public PrinterDiscoverySessionMediator(Context context) { 974 mHandler = new SessionHandler(context.getMainLooper()); 975 // Kick off the session creation. 976 List<RemotePrintService> services = new ArrayList<RemotePrintService>( 977 mActiveServices.values()); 978 mHandler.obtainMessage(SessionHandler 979 .MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION, services) 980 .sendToTarget(); 981 } 982 addObserverLocked(IPrinterDiscoveryObserver observer)983 public void addObserverLocked(IPrinterDiscoveryObserver observer) { 984 // Add the observer. 985 mDiscoveryObservers.register(observer); 986 987 // Bring the added observer up to speed with the printers. 988 if (!mPrinters.isEmpty()) { 989 List<PrinterInfo> printers = new ArrayList<PrinterInfo>(mPrinters.values()); 990 SomeArgs args = SomeArgs.obtain(); 991 args.arg1 = observer; 992 args.arg2 = printers; 993 mHandler.obtainMessage(SessionHandler.MSG_PRINTERS_ADDED, 994 args).sendToTarget(); 995 } 996 } 997 removeObserverLocked(IPrinterDiscoveryObserver observer)998 public void removeObserverLocked(IPrinterDiscoveryObserver observer) { 999 // Remove the observer. 1000 mDiscoveryObservers.unregister(observer); 1001 // No one else observing - then kill it. 1002 if (mDiscoveryObservers.getRegisteredCallbackCount() == 0) { 1003 destroyLocked(); 1004 } 1005 } 1006 startPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer, List<PrinterId> priorityList)1007 public final void startPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer, 1008 List<PrinterId> priorityList) { 1009 if (mIsDestroyed) { 1010 Log.w(LOG_TAG, "Not starting dicovery - session destroyed"); 1011 return; 1012 } 1013 1014 final boolean discoveryStarted = !mStartedPrinterDiscoveryTokens.isEmpty(); 1015 1016 // Remember we got a start request to match with an end. 1017 mStartedPrinterDiscoveryTokens.add(observer.asBinder()); 1018 1019 // If printer discovery is ongoing and the start request has a list 1020 // of printer to be checked, then we just request validating them. 1021 if (discoveryStarted && priorityList != null && !priorityList.isEmpty()) { 1022 validatePrinters(priorityList); 1023 return; 1024 } 1025 1026 // The service are already performing discovery - nothing to do. 1027 if (mStartedPrinterDiscoveryTokens.size() > 1) { 1028 return; 1029 } 1030 1031 List<RemotePrintService> services = new ArrayList<RemotePrintService>( 1032 mActiveServices.values()); 1033 SomeArgs args = SomeArgs.obtain(); 1034 args.arg1 = services; 1035 args.arg2 = priorityList; 1036 mHandler.obtainMessage(SessionHandler 1037 .MSG_DISPATCH_START_PRINTER_DISCOVERY, args) 1038 .sendToTarget(); 1039 } 1040 stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer)1041 public final void stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer) { 1042 if (mIsDestroyed) { 1043 Log.w(LOG_TAG, "Not stopping dicovery - session destroyed"); 1044 return; 1045 } 1046 // This one did not make an active discovery request - nothing to do. 1047 if (!mStartedPrinterDiscoveryTokens.remove(observer.asBinder())) { 1048 return; 1049 } 1050 // There are other interested observers - do not stop discovery. 1051 if (!mStartedPrinterDiscoveryTokens.isEmpty()) { 1052 return; 1053 } 1054 List<RemotePrintService> services = new ArrayList<RemotePrintService>( 1055 mActiveServices.values()); 1056 mHandler.obtainMessage(SessionHandler 1057 .MSG_DISPATCH_STOP_PRINTER_DISCOVERY, services) 1058 .sendToTarget(); 1059 } 1060 validatePrintersLocked(List<PrinterId> printerIds)1061 public void validatePrintersLocked(List<PrinterId> printerIds) { 1062 if (mIsDestroyed) { 1063 Log.w(LOG_TAG, "Not validating pritners - session destroyed"); 1064 return; 1065 } 1066 1067 List<PrinterId> remainingList = new ArrayList<PrinterId>(printerIds); 1068 while (!remainingList.isEmpty()) { 1069 Iterator<PrinterId> iterator = remainingList.iterator(); 1070 // Gather the printers per service and request a validation. 1071 List<PrinterId> updateList = new ArrayList<PrinterId>(); 1072 ComponentName serviceName = null; 1073 while (iterator.hasNext()) { 1074 PrinterId printerId = iterator.next(); 1075 if (updateList.isEmpty()) { 1076 updateList.add(printerId); 1077 serviceName = printerId.getServiceName(); 1078 iterator.remove(); 1079 } else if (printerId.getServiceName().equals(serviceName)) { 1080 updateList.add(printerId); 1081 iterator.remove(); 1082 } 1083 } 1084 // Schedule a notification of the service. 1085 RemotePrintService service = mActiveServices.get(serviceName); 1086 if (service != null) { 1087 SomeArgs args = SomeArgs.obtain(); 1088 args.arg1 = service; 1089 args.arg2 = updateList; 1090 mHandler.obtainMessage(SessionHandler 1091 .MSG_VALIDATE_PRINTERS, args) 1092 .sendToTarget(); 1093 } 1094 } 1095 } 1096 startPrinterStateTrackingLocked(PrinterId printerId)1097 public final void startPrinterStateTrackingLocked(PrinterId printerId) { 1098 if (mIsDestroyed) { 1099 Log.w(LOG_TAG, "Not starting printer state tracking - session destroyed"); 1100 return; 1101 } 1102 // If printer discovery is not started - nothing to do. 1103 if (mStartedPrinterDiscoveryTokens.isEmpty()) { 1104 return; 1105 } 1106 final boolean containedPrinterId = mStateTrackedPrinters.contains(printerId); 1107 // Keep track of the number of requests to track this one. 1108 mStateTrackedPrinters.add(printerId); 1109 // If we were tracking this printer - nothing to do. 1110 if (containedPrinterId) { 1111 return; 1112 } 1113 // No service - nothing to do. 1114 RemotePrintService service = mActiveServices.get(printerId.getServiceName()); 1115 if (service == null) { 1116 return; 1117 } 1118 // Ask the service to start tracking. 1119 SomeArgs args = SomeArgs.obtain(); 1120 args.arg1 = service; 1121 args.arg2 = printerId; 1122 mHandler.obtainMessage(SessionHandler 1123 .MSG_START_PRINTER_STATE_TRACKING, args) 1124 .sendToTarget(); 1125 } 1126 stopPrinterStateTrackingLocked(PrinterId printerId)1127 public final void stopPrinterStateTrackingLocked(PrinterId printerId) { 1128 if (mIsDestroyed) { 1129 Log.w(LOG_TAG, "Not stopping printer state tracking - session destroyed"); 1130 return; 1131 } 1132 // If printer discovery is not started - nothing to do. 1133 if (mStartedPrinterDiscoveryTokens.isEmpty()) { 1134 return; 1135 } 1136 // If we did not track this printer - nothing to do. 1137 if (!mStateTrackedPrinters.remove(printerId)) { 1138 return; 1139 } 1140 // No service - nothing to do. 1141 RemotePrintService service = mActiveServices.get(printerId.getServiceName()); 1142 if (service == null) { 1143 return; 1144 } 1145 // Ask the service to start tracking. 1146 SomeArgs args = SomeArgs.obtain(); 1147 args.arg1 = service; 1148 args.arg2 = printerId; 1149 mHandler.obtainMessage(SessionHandler 1150 .MSG_STOP_PRINTER_STATE_TRACKING, args) 1151 .sendToTarget(); 1152 } 1153 onDestroyed()1154 public void onDestroyed() { 1155 /* do nothing */ 1156 } 1157 destroyLocked()1158 public void destroyLocked() { 1159 if (mIsDestroyed) { 1160 Log.w(LOG_TAG, "Not destroying - session destroyed"); 1161 return; 1162 } 1163 mIsDestroyed = true; 1164 // Make sure printer tracking is stopped. 1165 final int printerCount = mStateTrackedPrinters.size(); 1166 for (int i = 0; i < printerCount; i++) { 1167 PrinterId printerId = mStateTrackedPrinters.get(i); 1168 stopPrinterStateTracking(printerId); 1169 } 1170 // Make sure discovery is stopped. 1171 final int observerCount = mStartedPrinterDiscoveryTokens.size(); 1172 for (int i = 0; i < observerCount; i++) { 1173 IBinder token = mStartedPrinterDiscoveryTokens.get(i); 1174 stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver.Stub.asInterface(token)); 1175 } 1176 // Tell the services we are done. 1177 List<RemotePrintService> services = new ArrayList<RemotePrintService>( 1178 mActiveServices.values()); 1179 mHandler.obtainMessage(SessionHandler 1180 .MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION, services) 1181 .sendToTarget(); 1182 } 1183 onPrintersAddedLocked(List<PrinterInfo> printers)1184 public void onPrintersAddedLocked(List<PrinterInfo> printers) { 1185 if (DEBUG) { 1186 Log.i(LOG_TAG, "onPrintersAddedLocked()"); 1187 } 1188 if (mIsDestroyed) { 1189 Log.w(LOG_TAG, "Not adding printers - session destroyed"); 1190 return; 1191 } 1192 List<PrinterInfo> addedPrinters = null; 1193 final int addedPrinterCount = printers.size(); 1194 for (int i = 0; i < addedPrinterCount; i++) { 1195 PrinterInfo printer = printers.get(i); 1196 PrinterInfo oldPrinter = mPrinters.put(printer.getId(), printer); 1197 if (oldPrinter == null || !oldPrinter.equals(printer)) { 1198 if (addedPrinters == null) { 1199 addedPrinters = new ArrayList<PrinterInfo>(); 1200 } 1201 addedPrinters.add(printer); 1202 } 1203 } 1204 if (addedPrinters != null) { 1205 mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED, 1206 addedPrinters).sendToTarget(); 1207 } 1208 } 1209 onPrintersRemovedLocked(List<PrinterId> printerIds)1210 public void onPrintersRemovedLocked(List<PrinterId> printerIds) { 1211 if (DEBUG) { 1212 Log.i(LOG_TAG, "onPrintersRemovedLocked()"); 1213 } 1214 if (mIsDestroyed) { 1215 Log.w(LOG_TAG, "Not removing printers - session destroyed"); 1216 return; 1217 } 1218 List<PrinterId> removedPrinterIds = null; 1219 final int removedPrinterCount = printerIds.size(); 1220 for (int i = 0; i < removedPrinterCount; i++) { 1221 PrinterId removedPrinterId = printerIds.get(i); 1222 if (mPrinters.remove(removedPrinterId) != null) { 1223 if (removedPrinterIds == null) { 1224 removedPrinterIds = new ArrayList<PrinterId>(); 1225 } 1226 removedPrinterIds.add(removedPrinterId); 1227 } 1228 } 1229 if (removedPrinterIds != null) { 1230 mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED, 1231 removedPrinterIds).sendToTarget(); 1232 } 1233 } 1234 onServiceRemovedLocked(RemotePrintService service)1235 public void onServiceRemovedLocked(RemotePrintService service) { 1236 if (mIsDestroyed) { 1237 Log.w(LOG_TAG, "Not updating removed service - session destroyed"); 1238 return; 1239 } 1240 // Remove the reported and tracked printers for that service. 1241 ComponentName serviceName = service.getComponentName(); 1242 removePrintersForServiceLocked(serviceName); 1243 service.destroy(); 1244 } 1245 onServiceDiedLocked(RemotePrintService service)1246 public void onServiceDiedLocked(RemotePrintService service) { 1247 // Remove the reported by that service. 1248 removePrintersForServiceLocked(service.getComponentName()); 1249 } 1250 onServiceAddedLocked(RemotePrintService service)1251 public void onServiceAddedLocked(RemotePrintService service) { 1252 if (mIsDestroyed) { 1253 Log.w(LOG_TAG, "Not updating added service - session destroyed"); 1254 return; 1255 } 1256 // Tell the service to create a session. 1257 mHandler.obtainMessage( 1258 SessionHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION, 1259 service).sendToTarget(); 1260 // Start printer discovery if necessary. 1261 if (!mStartedPrinterDiscoveryTokens.isEmpty()) { 1262 mHandler.obtainMessage( 1263 SessionHandler.MSG_START_PRINTER_DISCOVERY, 1264 service).sendToTarget(); 1265 } 1266 // Start tracking printers if necessary 1267 final int trackedPrinterCount = mStateTrackedPrinters.size(); 1268 for (int i = 0; i < trackedPrinterCount; i++) { 1269 PrinterId printerId = mStateTrackedPrinters.get(i); 1270 if (printerId.getServiceName().equals(service.getComponentName())) { 1271 SomeArgs args = SomeArgs.obtain(); 1272 args.arg1 = service; 1273 args.arg2 = printerId; 1274 mHandler.obtainMessage(SessionHandler 1275 .MSG_START_PRINTER_STATE_TRACKING, args) 1276 .sendToTarget(); 1277 } 1278 } 1279 } 1280 dump(PrintWriter pw, String prefix)1281 public void dump(PrintWriter pw, String prefix) { 1282 pw.append(prefix).append("destroyed=") 1283 .append(String.valueOf(mDestroyed)).println(); 1284 1285 pw.append(prefix).append("printDiscoveryInProgress=") 1286 .append(String.valueOf(!mStartedPrinterDiscoveryTokens.isEmpty())).println(); 1287 1288 String tab = " "; 1289 1290 pw.append(prefix).append(tab).append("printer discovery observers:").println(); 1291 final int observerCount = mDiscoveryObservers.beginBroadcast(); 1292 for (int i = 0; i < observerCount; i++) { 1293 IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i); 1294 pw.append(prefix).append(prefix).append(observer.toString()); 1295 pw.println(); 1296 } 1297 mDiscoveryObservers.finishBroadcast(); 1298 1299 pw.append(prefix).append(tab).append("start discovery requests:").println(); 1300 final int tokenCount = this.mStartedPrinterDiscoveryTokens.size(); 1301 for (int i = 0; i < tokenCount; i++) { 1302 IBinder token = mStartedPrinterDiscoveryTokens.get(i); 1303 pw.append(prefix).append(tab).append(tab).append(token.toString()).println(); 1304 } 1305 1306 pw.append(prefix).append(tab).append("tracked printer requests:").println(); 1307 final int trackedPrinters = mStateTrackedPrinters.size(); 1308 for (int i = 0; i < trackedPrinters; i++) { 1309 PrinterId printer = mStateTrackedPrinters.get(i); 1310 pw.append(prefix).append(tab).append(tab).append(printer.toString()).println(); 1311 } 1312 1313 pw.append(prefix).append(tab).append("printers:").println(); 1314 final int pritnerCount = mPrinters.size(); 1315 for (int i = 0; i < pritnerCount; i++) { 1316 PrinterInfo printer = mPrinters.valueAt(i); 1317 pw.append(prefix).append(tab).append(tab).append( 1318 printer.toString()).println(); 1319 } 1320 } 1321 removePrintersForServiceLocked(ComponentName serviceName)1322 private void removePrintersForServiceLocked(ComponentName serviceName) { 1323 // No printers - nothing to do. 1324 if (mPrinters.isEmpty()) { 1325 return; 1326 } 1327 // Remove the printers for that service. 1328 List<PrinterId> removedPrinterIds = null; 1329 final int printerCount = mPrinters.size(); 1330 for (int i = 0; i < printerCount; i++) { 1331 PrinterId printerId = mPrinters.keyAt(i); 1332 if (printerId.getServiceName().equals(serviceName)) { 1333 if (removedPrinterIds == null) { 1334 removedPrinterIds = new ArrayList<PrinterId>(); 1335 } 1336 removedPrinterIds.add(printerId); 1337 } 1338 } 1339 if (removedPrinterIds != null) { 1340 final int removedPrinterCount = removedPrinterIds.size(); 1341 for (int i = 0; i < removedPrinterCount; i++) { 1342 mPrinters.remove(removedPrinterIds.get(i)); 1343 } 1344 mHandler.obtainMessage( 1345 SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED, 1346 removedPrinterIds).sendToTarget(); 1347 } 1348 } 1349 handleDispatchPrintersAdded(List<PrinterInfo> addedPrinters)1350 private void handleDispatchPrintersAdded(List<PrinterInfo> addedPrinters) { 1351 final int observerCount = mDiscoveryObservers.beginBroadcast(); 1352 for (int i = 0; i < observerCount; i++) { 1353 IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i); 1354 handlePrintersAdded(observer, addedPrinters); 1355 } 1356 mDiscoveryObservers.finishBroadcast(); 1357 } 1358 handleDispatchPrintersRemoved(List<PrinterId> removedPrinterIds)1359 private void handleDispatchPrintersRemoved(List<PrinterId> removedPrinterIds) { 1360 final int observerCount = mDiscoveryObservers.beginBroadcast(); 1361 for (int i = 0; i < observerCount; i++) { 1362 IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i); 1363 handlePrintersRemoved(observer, removedPrinterIds); 1364 } 1365 mDiscoveryObservers.finishBroadcast(); 1366 } 1367 handleDispatchCreatePrinterDiscoverySession( List<RemotePrintService> services)1368 private void handleDispatchCreatePrinterDiscoverySession( 1369 List<RemotePrintService> services) { 1370 final int serviceCount = services.size(); 1371 for (int i = 0; i < serviceCount; i++) { 1372 RemotePrintService service = services.get(i); 1373 service.createPrinterDiscoverySession(); 1374 } 1375 } 1376 handleDispatchDestroyPrinterDiscoverySession( List<RemotePrintService> services)1377 private void handleDispatchDestroyPrinterDiscoverySession( 1378 List<RemotePrintService> services) { 1379 final int serviceCount = services.size(); 1380 for (int i = 0; i < serviceCount; i++) { 1381 RemotePrintService service = services.get(i); 1382 service.destroyPrinterDiscoverySession(); 1383 } 1384 onDestroyed(); 1385 } 1386 handleDispatchStartPrinterDiscovery( List<RemotePrintService> services, List<PrinterId> printerIds)1387 private void handleDispatchStartPrinterDiscovery( 1388 List<RemotePrintService> services, List<PrinterId> printerIds) { 1389 final int serviceCount = services.size(); 1390 for (int i = 0; i < serviceCount; i++) { 1391 RemotePrintService service = services.get(i); 1392 service.startPrinterDiscovery(printerIds); 1393 } 1394 } 1395 handleDispatchStopPrinterDiscovery(List<RemotePrintService> services)1396 private void handleDispatchStopPrinterDiscovery(List<RemotePrintService> services) { 1397 final int serviceCount = services.size(); 1398 for (int i = 0; i < serviceCount; i++) { 1399 RemotePrintService service = services.get(i); 1400 service.stopPrinterDiscovery(); 1401 } 1402 } 1403 handleValidatePrinters(RemotePrintService service, List<PrinterId> printerIds)1404 private void handleValidatePrinters(RemotePrintService service, 1405 List<PrinterId> printerIds) { 1406 service.validatePrinters(printerIds); 1407 } 1408 handleStartPrinterStateTracking(RemotePrintService service, PrinterId printerId)1409 private void handleStartPrinterStateTracking(RemotePrintService service, 1410 PrinterId printerId) { 1411 service.startPrinterStateTracking(printerId); 1412 } 1413 handleStopPrinterStateTracking(RemotePrintService service, PrinterId printerId)1414 private void handleStopPrinterStateTracking(RemotePrintService service, 1415 PrinterId printerId) { 1416 service.stopPrinterStateTracking(printerId); 1417 } 1418 handlePrintersAdded(IPrinterDiscoveryObserver observer, List<PrinterInfo> printers)1419 private void handlePrintersAdded(IPrinterDiscoveryObserver observer, 1420 List<PrinterInfo> printers) { 1421 try { 1422 observer.onPrintersAdded(new ParceledListSlice<PrinterInfo>(printers)); 1423 } catch (RemoteException re) { 1424 Log.e(LOG_TAG, "Error sending added printers", re); 1425 } 1426 } 1427 handlePrintersRemoved(IPrinterDiscoveryObserver observer, List<PrinterId> printerIds)1428 private void handlePrintersRemoved(IPrinterDiscoveryObserver observer, 1429 List<PrinterId> printerIds) { 1430 try { 1431 observer.onPrintersRemoved(new ParceledListSlice<PrinterId>(printerIds)); 1432 } catch (RemoteException re) { 1433 Log.e(LOG_TAG, "Error sending removed printers", re); 1434 } 1435 } 1436 1437 private final class SessionHandler extends Handler { 1438 public static final int MSG_PRINTERS_ADDED = 1; 1439 public static final int MSG_PRINTERS_REMOVED = 2; 1440 public static final int MSG_DISPATCH_PRINTERS_ADDED = 3; 1441 public static final int MSG_DISPATCH_PRINTERS_REMOVED = 4; 1442 1443 public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 5; 1444 public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 6; 1445 public static final int MSG_START_PRINTER_DISCOVERY = 7; 1446 public static final int MSG_STOP_PRINTER_DISCOVERY = 8; 1447 public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 9; 1448 public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 10; 1449 public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 11; 1450 public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 12; 1451 public static final int MSG_VALIDATE_PRINTERS = 13; 1452 public static final int MSG_START_PRINTER_STATE_TRACKING = 14; 1453 public static final int MSG_STOP_PRINTER_STATE_TRACKING = 15; 1454 public static final int MSG_DESTROY_SERVICE = 16; 1455 SessionHandler(Looper looper)1456 SessionHandler(Looper looper) { 1457 super(looper, null, false); 1458 } 1459 1460 @Override 1461 @SuppressWarnings("unchecked") handleMessage(Message message)1462 public void handleMessage(Message message) { 1463 switch (message.what) { 1464 case MSG_PRINTERS_ADDED: { 1465 SomeArgs args = (SomeArgs) message.obj; 1466 IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg1; 1467 List<PrinterInfo> addedPrinters = (List<PrinterInfo>) args.arg2; 1468 args.recycle(); 1469 handlePrintersAdded(observer, addedPrinters); 1470 } break; 1471 1472 case MSG_PRINTERS_REMOVED: { 1473 SomeArgs args = (SomeArgs) message.obj; 1474 IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg1; 1475 List<PrinterId> removedPrinterIds = (List<PrinterId>) args.arg2; 1476 args.recycle(); 1477 handlePrintersRemoved(observer, removedPrinterIds); 1478 } 1479 1480 case MSG_DISPATCH_PRINTERS_ADDED: { 1481 List<PrinterInfo> addedPrinters = (List<PrinterInfo>) message.obj; 1482 handleDispatchPrintersAdded(addedPrinters); 1483 } break; 1484 1485 case MSG_DISPATCH_PRINTERS_REMOVED: { 1486 List<PrinterId> removedPrinterIds = (List<PrinterId>) message.obj; 1487 handleDispatchPrintersRemoved(removedPrinterIds); 1488 } break; 1489 1490 case MSG_CREATE_PRINTER_DISCOVERY_SESSION: { 1491 RemotePrintService service = (RemotePrintService) message.obj; 1492 service.createPrinterDiscoverySession(); 1493 } break; 1494 1495 case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: { 1496 RemotePrintService service = (RemotePrintService) message.obj; 1497 service.destroyPrinterDiscoverySession(); 1498 } break; 1499 1500 case MSG_START_PRINTER_DISCOVERY: { 1501 RemotePrintService service = (RemotePrintService) message.obj; 1502 service.startPrinterDiscovery(null); 1503 } break; 1504 1505 case MSG_STOP_PRINTER_DISCOVERY: { 1506 RemotePrintService service = (RemotePrintService) message.obj; 1507 service.stopPrinterDiscovery(); 1508 } break; 1509 1510 case MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION: { 1511 List<RemotePrintService> services = (List<RemotePrintService>) message.obj; 1512 handleDispatchCreatePrinterDiscoverySession(services); 1513 } break; 1514 1515 case MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION: { 1516 List<RemotePrintService> services = (List<RemotePrintService>) message.obj; 1517 handleDispatchDestroyPrinterDiscoverySession(services); 1518 } break; 1519 1520 case MSG_DISPATCH_START_PRINTER_DISCOVERY: { 1521 SomeArgs args = (SomeArgs) message.obj; 1522 List<RemotePrintService> services = (List<RemotePrintService>) args.arg1; 1523 List<PrinterId> printerIds = (List<PrinterId>) args.arg2; 1524 args.recycle(); 1525 handleDispatchStartPrinterDiscovery(services, printerIds); 1526 } break; 1527 1528 case MSG_DISPATCH_STOP_PRINTER_DISCOVERY: { 1529 List<RemotePrintService> services = (List<RemotePrintService>) message.obj; 1530 handleDispatchStopPrinterDiscovery(services); 1531 } break; 1532 1533 case MSG_VALIDATE_PRINTERS: { 1534 SomeArgs args = (SomeArgs) message.obj; 1535 RemotePrintService service = (RemotePrintService) args.arg1; 1536 List<PrinterId> printerIds = (List<PrinterId>) args.arg2; 1537 args.recycle(); 1538 handleValidatePrinters(service, printerIds); 1539 } break; 1540 1541 case MSG_START_PRINTER_STATE_TRACKING: { 1542 SomeArgs args = (SomeArgs) message.obj; 1543 RemotePrintService service = (RemotePrintService) args.arg1; 1544 PrinterId printerId = (PrinterId) args.arg2; 1545 args.recycle(); 1546 handleStartPrinterStateTracking(service, printerId); 1547 } break; 1548 1549 case MSG_STOP_PRINTER_STATE_TRACKING: { 1550 SomeArgs args = (SomeArgs) message.obj; 1551 RemotePrintService service = (RemotePrintService) args.arg1; 1552 PrinterId printerId = (PrinterId) args.arg2; 1553 args.recycle(); 1554 handleStopPrinterStateTracking(service, printerId); 1555 } break; 1556 1557 case MSG_DESTROY_SERVICE: { 1558 RemotePrintService service = (RemotePrintService) message.obj; 1559 service.destroy(); 1560 } break; 1561 } 1562 } 1563 } 1564 } 1565 1566 private final class PrintJobForAppCache { 1567 private final SparseArray<List<PrintJobInfo>> mPrintJobsForRunningApp = 1568 new SparseArray<List<PrintJobInfo>>(); 1569 onPrintJobCreated(final IBinder creator, final int appId, PrintJobInfo printJob)1570 public boolean onPrintJobCreated(final IBinder creator, final int appId, 1571 PrintJobInfo printJob) { 1572 try { 1573 creator.linkToDeath(new DeathRecipient() { 1574 @Override 1575 public void binderDied() { 1576 creator.unlinkToDeath(this, 0); 1577 synchronized (mLock) { 1578 mPrintJobsForRunningApp.remove(appId); 1579 } 1580 } 1581 }, 0); 1582 } catch (RemoteException re) { 1583 /* The process is already dead - we just failed. */ 1584 return false; 1585 } 1586 synchronized (mLock) { 1587 List<PrintJobInfo> printJobsForApp = mPrintJobsForRunningApp.get(appId); 1588 if (printJobsForApp == null) { 1589 printJobsForApp = new ArrayList<PrintJobInfo>(); 1590 mPrintJobsForRunningApp.put(appId, printJobsForApp); 1591 } 1592 printJobsForApp.add(printJob); 1593 } 1594 return true; 1595 } 1596 onPrintJobStateChanged(PrintJobInfo printJob)1597 public void onPrintJobStateChanged(PrintJobInfo printJob) { 1598 synchronized (mLock) { 1599 List<PrintJobInfo> printJobsForApp = mPrintJobsForRunningApp.get( 1600 printJob.getAppId()); 1601 if (printJobsForApp == null) { 1602 return; 1603 } 1604 final int printJobCount = printJobsForApp.size(); 1605 for (int i = 0; i < printJobCount; i++) { 1606 PrintJobInfo oldPrintJob = printJobsForApp.get(i); 1607 if (oldPrintJob.getId().equals(printJob.getId())) { 1608 printJobsForApp.set(i, printJob); 1609 } 1610 } 1611 } 1612 } 1613 getPrintJob(PrintJobId printJobId, int appId)1614 public PrintJobInfo getPrintJob(PrintJobId printJobId, int appId) { 1615 synchronized (mLock) { 1616 List<PrintJobInfo> printJobsForApp = mPrintJobsForRunningApp.get(appId); 1617 if (printJobsForApp == null) { 1618 return null; 1619 } 1620 final int printJobCount = printJobsForApp.size(); 1621 for (int i = 0; i < printJobCount; i++) { 1622 PrintJobInfo printJob = printJobsForApp.get(i); 1623 if (printJob.getId().equals(printJobId)) { 1624 return printJob; 1625 } 1626 } 1627 } 1628 return null; 1629 } 1630 getPrintJobs(int appId)1631 public List<PrintJobInfo> getPrintJobs(int appId) { 1632 synchronized (mLock) { 1633 List<PrintJobInfo> printJobs = null; 1634 if (appId == PrintManager.APP_ID_ANY) { 1635 final int bucketCount = mPrintJobsForRunningApp.size(); 1636 for (int i = 0; i < bucketCount; i++) { 1637 List<PrintJobInfo> bucket = mPrintJobsForRunningApp.valueAt(i); 1638 if (printJobs == null) { 1639 printJobs = new ArrayList<PrintJobInfo>(); 1640 } 1641 printJobs.addAll(bucket); 1642 } 1643 } else { 1644 List<PrintJobInfo> bucket = mPrintJobsForRunningApp.get(appId); 1645 if (bucket != null) { 1646 if (printJobs == null) { 1647 printJobs = new ArrayList<PrintJobInfo>(); 1648 } 1649 printJobs.addAll(bucket); 1650 } 1651 } 1652 if (printJobs != null) { 1653 return printJobs; 1654 } 1655 return Collections.emptyList(); 1656 } 1657 } 1658 dump(PrintWriter pw, String prefix)1659 public void dump(PrintWriter pw, String prefix) { 1660 synchronized (mLock) { 1661 String tab = " "; 1662 final int bucketCount = mPrintJobsForRunningApp.size(); 1663 for (int i = 0; i < bucketCount; i++) { 1664 final int appId = mPrintJobsForRunningApp.keyAt(i); 1665 pw.append(prefix).append("appId=" + appId).append(':').println(); 1666 List<PrintJobInfo> bucket = mPrintJobsForRunningApp.valueAt(i); 1667 final int printJobCount = bucket.size(); 1668 for (int j = 0; j < printJobCount; j++) { 1669 PrintJobInfo printJob = bucket.get(j); 1670 pw.append(prefix).append(tab).append(printJob.toString()).println(); 1671 } 1672 } 1673 } 1674 } 1675 } 1676 } 1677