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