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.annotation.FloatRange; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.StringRes; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.ServiceConnection; 27 import android.graphics.drawable.Icon; 28 import android.os.Binder; 29 import android.os.Build; 30 import android.os.IBinder; 31 import android.os.ParcelFileDescriptor; 32 import android.os.RemoteException; 33 import android.os.SystemClock; 34 import android.os.UserHandle; 35 import android.print.IPrintSpooler; 36 import android.print.IPrintSpoolerCallbacks; 37 import android.print.IPrintSpoolerClient; 38 import android.print.PrintJobId; 39 import android.print.PrintJobInfo; 40 import android.print.PrintManager; 41 import android.print.PrinterId; 42 import android.printservice.PrintService; 43 import android.util.Slog; 44 import android.util.TimedRemoteCaller; 45 46 import libcore.io.IoUtils; 47 48 import java.io.FileDescriptor; 49 import java.io.PrintWriter; 50 import java.lang.ref.WeakReference; 51 import java.util.List; 52 import java.util.concurrent.TimeoutException; 53 54 /** 55 * This represents the remote print spooler as a local object to the 56 * PrintManagerService. It is responsible to connecting to the remote 57 * spooler if needed, to make the timed remote calls, to handle 58 * remote exceptions, and to bind/unbind to the remote instance as 59 * needed. 60 */ 61 final class RemotePrintSpooler { 62 63 private static final String LOG_TAG = "RemotePrintSpooler"; 64 65 private static final boolean DEBUG = false; 66 67 private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 68 ("eng".equals(Build.TYPE)) ? 120000 : 10000; 69 70 private final Object mLock = new Object(); 71 72 private final GetPrintJobInfosCaller mGetPrintJobInfosCaller = new GetPrintJobInfosCaller(); 73 74 private final GetPrintJobInfoCaller mGetPrintJobInfoCaller = new GetPrintJobInfoCaller(); 75 76 private final SetPrintJobStateCaller mSetPrintJobStatusCaller = new SetPrintJobStateCaller(); 77 78 private final SetPrintJobTagCaller mSetPrintJobTagCaller = new SetPrintJobTagCaller(); 79 80 private final OnCustomPrinterIconLoadedCaller mCustomPrinterIconLoadedCaller = 81 new OnCustomPrinterIconLoadedCaller(); 82 83 private final ClearCustomPrinterIconCacheCaller mClearCustomPrinterIconCache = 84 new ClearCustomPrinterIconCacheCaller(); 85 86 private final GetCustomPrinterIconCaller mGetCustomPrinterIconCaller = 87 new GetCustomPrinterIconCaller(); 88 89 private final ServiceConnection mServiceConnection = new MyServiceConnection(); 90 91 private final Context mContext; 92 93 private final UserHandle mUserHandle; 94 95 private final PrintSpoolerClient mClient; 96 97 private final Intent mIntent; 98 99 private final PrintSpoolerCallbacks mCallbacks; 100 101 private boolean mIsLowPriority; 102 103 private IPrintSpooler mRemoteInstance; 104 105 private boolean mDestroyed; 106 107 private boolean mCanUnbind; 108 109 public static interface PrintSpoolerCallbacks { 110 public void onPrintJobQueued(PrintJobInfo printJob); 111 public void onAllPrintJobsForServiceHandled(ComponentName printService); 112 public void onPrintJobStateChanged(PrintJobInfo printJob); 113 } 114 115 public RemotePrintSpooler(Context context, int userId, boolean lowPriority, 116 PrintSpoolerCallbacks callbacks) { 117 mContext = context; 118 mUserHandle = new UserHandle(userId); 119 mCallbacks = callbacks; 120 mIsLowPriority = lowPriority; 121 mClient = new PrintSpoolerClient(this); 122 mIntent = new Intent(); 123 mIntent.setComponent(new ComponentName(PrintManager.PRINT_SPOOLER_PACKAGE_NAME, 124 PrintManager.PRINT_SPOOLER_PACKAGE_NAME + ".model.PrintSpoolerService")); 125 } 126 127 public void increasePriority() { 128 if (mIsLowPriority) { 129 mIsLowPriority = false; 130 131 synchronized (mLock) { 132 throwIfDestroyedLocked(); 133 134 while (!mCanUnbind) { 135 try { 136 mLock.wait(); 137 } catch (InterruptedException e) { 138 Slog.e(LOG_TAG, "Interrupted while waiting for operation to complete"); 139 } 140 } 141 142 if (DEBUG) { 143 Slog.i(LOG_TAG, "Unbinding as previous binding was low priority"); 144 } 145 146 unbindLocked(); 147 } 148 } 149 } 150 151 public final List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, int state, 152 int appId) { 153 throwIfCalledOnMainThread(); 154 synchronized (mLock) { 155 throwIfDestroyedLocked(); 156 mCanUnbind = false; 157 } 158 try { 159 return mGetPrintJobInfosCaller.getPrintJobInfos(getRemoteInstanceLazy(), 160 componentName, state, appId); 161 } catch (RemoteException re) { 162 Slog.e(LOG_TAG, "Error getting print jobs.", re); 163 } catch (TimeoutException te) { 164 Slog.e(LOG_TAG, "Error getting print jobs.", te); 165 } finally { 166 if (DEBUG) { 167 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfos()"); 168 } 169 synchronized (mLock) { 170 mCanUnbind = true; 171 mLock.notifyAll(); 172 } 173 } 174 return null; 175 } 176 177 public final void createPrintJob(PrintJobInfo printJob) { 178 throwIfCalledOnMainThread(); 179 synchronized (mLock) { 180 throwIfDestroyedLocked(); 181 mCanUnbind = false; 182 } 183 try { 184 getRemoteInstanceLazy().createPrintJob(printJob); 185 } catch (RemoteException re) { 186 Slog.e(LOG_TAG, "Error creating print job.", re); 187 } catch (TimeoutException te) { 188 Slog.e(LOG_TAG, "Error creating print job.", te); 189 } finally { 190 if (DEBUG) { 191 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] createPrintJob()"); 192 } 193 synchronized (mLock) { 194 mCanUnbind = true; 195 mLock.notifyAll(); 196 } 197 } 198 } 199 200 public final void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) { 201 throwIfCalledOnMainThread(); 202 synchronized (mLock) { 203 throwIfDestroyedLocked(); 204 mCanUnbind = false; 205 } 206 try { 207 getRemoteInstanceLazy().writePrintJobData(fd, printJobId); 208 } catch (RemoteException re) { 209 Slog.e(LOG_TAG, "Error writing print job data.", re); 210 } catch (TimeoutException te) { 211 Slog.e(LOG_TAG, "Error writing print job data.", te); 212 } finally { 213 if (DEBUG) { 214 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] writePrintJobData()"); 215 } 216 // We passed the file descriptor across and now the other 217 // side is responsible to close it, so close the local copy. 218 IoUtils.closeQuietly(fd); 219 synchronized (mLock) { 220 mCanUnbind = true; 221 mLock.notifyAll(); 222 } 223 } 224 } 225 226 public final PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) { 227 throwIfCalledOnMainThread(); 228 synchronized (mLock) { 229 throwIfDestroyedLocked(); 230 mCanUnbind = false; 231 } 232 try { 233 return mGetPrintJobInfoCaller.getPrintJobInfo(getRemoteInstanceLazy(), 234 printJobId, appId); 235 } catch (RemoteException re) { 236 Slog.e(LOG_TAG, "Error getting print job info.", re); 237 } catch (TimeoutException te) { 238 Slog.e(LOG_TAG, "Error getting print job info.", te); 239 } finally { 240 if (DEBUG) { 241 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfo()"); 242 } 243 synchronized (mLock) { 244 mCanUnbind = true; 245 mLock.notifyAll(); 246 } 247 } 248 return null; 249 } 250 251 public final boolean setPrintJobState(PrintJobId printJobId, int state, String error) { 252 throwIfCalledOnMainThread(); 253 synchronized (mLock) { 254 throwIfDestroyedLocked(); 255 mCanUnbind = false; 256 } 257 try { 258 return mSetPrintJobStatusCaller.setPrintJobState(getRemoteInstanceLazy(), 259 printJobId, state, error); 260 } catch (RemoteException re) { 261 Slog.e(LOG_TAG, "Error setting print job state.", re); 262 } catch (TimeoutException te) { 263 Slog.e(LOG_TAG, "Error setting print job state.", te); 264 } finally { 265 if (DEBUG) { 266 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobState()"); 267 } 268 synchronized (mLock) { 269 mCanUnbind = true; 270 mLock.notifyAll(); 271 } 272 } 273 return false; 274 } 275 276 /** 277 * Set progress of a print job. 278 * 279 * @param printJobId The print job to update 280 * @param progress The new progress 281 */ 282 public final void setProgress(@NonNull PrintJobId printJobId, 283 @FloatRange(from=0.0, to=1.0) float progress) { 284 throwIfCalledOnMainThread(); 285 synchronized (mLock) { 286 throwIfDestroyedLocked(); 287 mCanUnbind = false; 288 } 289 try { 290 getRemoteInstanceLazy().setProgress(printJobId, progress); 291 } catch (RemoteException|TimeoutException re) { 292 Slog.e(LOG_TAG, "Error setting progress.", re); 293 } finally { 294 if (DEBUG) { 295 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setProgress()"); 296 } 297 synchronized (mLock) { 298 mCanUnbind = true; 299 mLock.notifyAll(); 300 } 301 } 302 } 303 304 /** 305 * Set status of a print job. 306 * 307 * @param printJobId The print job to update 308 * @param status The new status 309 */ 310 public final void setStatus(@NonNull PrintJobId printJobId, @Nullable CharSequence status) { 311 throwIfCalledOnMainThread(); 312 synchronized (mLock) { 313 throwIfDestroyedLocked(); 314 mCanUnbind = false; 315 } 316 try { 317 getRemoteInstanceLazy().setStatus(printJobId, status); 318 } catch (RemoteException|TimeoutException re) { 319 Slog.e(LOG_TAG, "Error setting status.", re); 320 } finally { 321 if (DEBUG) { 322 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setStatus()"); 323 } 324 synchronized (mLock) { 325 mCanUnbind = true; 326 mLock.notifyAll(); 327 } 328 } 329 } 330 331 /** 332 * Set status of a print job. 333 * 334 * @param printJobId The print job to update 335 * @param status The new status as a string resource 336 * @param appPackageName The app package name the string res belongs to 337 */ 338 public final void setStatus(@NonNull PrintJobId printJobId, @StringRes int status, 339 @NonNull CharSequence appPackageName) { 340 throwIfCalledOnMainThread(); 341 synchronized (mLock) { 342 throwIfDestroyedLocked(); 343 mCanUnbind = false; 344 } 345 try { 346 getRemoteInstanceLazy().setStatusRes(printJobId, status, appPackageName); 347 } catch (RemoteException|TimeoutException re) { 348 Slog.e(LOG_TAG, "Error setting status.", re); 349 } finally { 350 if (DEBUG) { 351 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setStatus()"); 352 } 353 synchronized (mLock) { 354 mCanUnbind = true; 355 mLock.notifyAll(); 356 } 357 } 358 } 359 360 /** 361 * Handle that a custom icon for a printer was loaded. 362 * 363 * @param printerId the id of the printer the icon belongs to 364 * @param icon the icon that was loaded 365 * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon() 366 */ 367 public final void onCustomPrinterIconLoaded(@NonNull PrinterId printerId, 368 @Nullable Icon icon) { 369 throwIfCalledOnMainThread(); 370 synchronized (mLock) { 371 throwIfDestroyedLocked(); 372 mCanUnbind = false; 373 } 374 try { 375 mCustomPrinterIconLoadedCaller.onCustomPrinterIconLoaded(getRemoteInstanceLazy(), 376 printerId, icon); 377 } catch (RemoteException|TimeoutException re) { 378 Slog.e(LOG_TAG, "Error loading new custom printer icon.", re); 379 } finally { 380 if (DEBUG) { 381 Slog.i(LOG_TAG, 382 "[user: " + mUserHandle.getIdentifier() + "] onCustomPrinterIconLoaded()"); 383 } 384 synchronized (mLock) { 385 mCanUnbind = true; 386 mLock.notifyAll(); 387 } 388 } 389 } 390 391 /** 392 * Get the custom icon for a printer. If the icon is not cached, the icon is 393 * requested asynchronously. Once it is available the printer is updated. 394 * 395 * @param printerId the id of the printer the icon should be loaded for 396 * @return the custom icon to be used for the printer or null if the icon is 397 * not yet available 398 * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon() 399 */ 400 public final @Nullable Icon getCustomPrinterIcon(@NonNull PrinterId printerId) { 401 throwIfCalledOnMainThread(); 402 synchronized (mLock) { 403 throwIfDestroyedLocked(); 404 mCanUnbind = false; 405 } 406 try { 407 return mGetCustomPrinterIconCaller.getCustomPrinterIcon(getRemoteInstanceLazy(), 408 printerId); 409 } catch (RemoteException|TimeoutException re) { 410 Slog.e(LOG_TAG, "Error getting custom printer icon.", re); 411 return null; 412 } finally { 413 if (DEBUG) { 414 Slog.i(LOG_TAG, 415 "[user: " + mUserHandle.getIdentifier() + "] getCustomPrinterIcon()"); 416 } 417 synchronized (mLock) { 418 mCanUnbind = true; 419 mLock.notifyAll(); 420 } 421 } 422 } 423 424 /** 425 * Clear the custom printer icon cache 426 */ 427 public void clearCustomPrinterIconCache() { 428 throwIfCalledOnMainThread(); 429 synchronized (mLock) { 430 throwIfDestroyedLocked(); 431 mCanUnbind = false; 432 } 433 try { 434 mClearCustomPrinterIconCache.clearCustomPrinterIconCache(getRemoteInstanceLazy()); 435 } catch (RemoteException|TimeoutException re) { 436 Slog.e(LOG_TAG, "Error clearing custom printer icon cache.", re); 437 } finally { 438 if (DEBUG) { 439 Slog.i(LOG_TAG, 440 "[user: " + mUserHandle.getIdentifier() 441 + "] clearCustomPrinterIconCache()"); 442 } 443 synchronized (mLock) { 444 mCanUnbind = true; 445 mLock.notifyAll(); 446 } 447 } 448 } 449 450 public final boolean setPrintJobTag(PrintJobId printJobId, String tag) { 451 throwIfCalledOnMainThread(); 452 synchronized (mLock) { 453 throwIfDestroyedLocked(); 454 mCanUnbind = false; 455 } 456 try { 457 return mSetPrintJobTagCaller.setPrintJobTag(getRemoteInstanceLazy(), 458 printJobId, tag); 459 } catch (RemoteException re) { 460 Slog.e(LOG_TAG, "Error setting print job tag.", re); 461 } catch (TimeoutException te) { 462 Slog.e(LOG_TAG, "Error setting print job tag.", te); 463 } finally { 464 if (DEBUG) { 465 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobTag()"); 466 } 467 synchronized (mLock) { 468 mCanUnbind = true; 469 mLock.notifyAll(); 470 } 471 } 472 return false; 473 } 474 475 public final void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) { 476 throwIfCalledOnMainThread(); 477 synchronized (mLock) { 478 throwIfDestroyedLocked(); 479 mCanUnbind = false; 480 } 481 try { 482 getRemoteInstanceLazy().setPrintJobCancelling(printJobId, 483 cancelling); 484 } catch (RemoteException re) { 485 Slog.e(LOG_TAG, "Error setting print job cancelling.", re); 486 } catch (TimeoutException te) { 487 Slog.e(LOG_TAG, "Error setting print job cancelling.", te); 488 } finally { 489 if (DEBUG) { 490 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() 491 + "] setPrintJobCancelling()"); 492 } 493 synchronized (mLock) { 494 mCanUnbind = true; 495 mLock.notifyAll(); 496 } 497 } 498 } 499 500 /** 501 * Remove all approved {@link PrintService print services} that are not in the given set. 502 * 503 * @param servicesToKeep The {@link ComponentName names } of the services to keep 504 */ 505 public final void pruneApprovedPrintServices(List<ComponentName> servicesToKeep) { 506 throwIfCalledOnMainThread(); 507 synchronized (mLock) { 508 throwIfDestroyedLocked(); 509 mCanUnbind = false; 510 } 511 try { 512 getRemoteInstanceLazy().pruneApprovedPrintServices(servicesToKeep); 513 } catch (RemoteException|TimeoutException re) { 514 Slog.e(LOG_TAG, "Error pruning approved print services.", re); 515 } finally { 516 if (DEBUG) { 517 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() 518 + "] pruneApprovedPrintServices()"); 519 } 520 synchronized (mLock) { 521 mCanUnbind = true; 522 mLock.notifyAll(); 523 } 524 } 525 } 526 527 public final void removeObsoletePrintJobs() { 528 throwIfCalledOnMainThread(); 529 synchronized (mLock) { 530 throwIfDestroyedLocked(); 531 mCanUnbind = false; 532 } 533 try { 534 getRemoteInstanceLazy().removeObsoletePrintJobs(); 535 } catch (RemoteException re) { 536 Slog.e(LOG_TAG, "Error removing obsolete print jobs .", re); 537 } catch (TimeoutException te) { 538 Slog.e(LOG_TAG, "Error removing obsolete print jobs .", te); 539 } finally { 540 if (DEBUG) { 541 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() 542 + "] removeObsoletePrintJobs()"); 543 } 544 synchronized (mLock) { 545 mCanUnbind = true; 546 mLock.notifyAll(); 547 } 548 } 549 } 550 551 public final void destroy() { 552 throwIfCalledOnMainThread(); 553 if (DEBUG) { 554 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] destroy()"); 555 } 556 synchronized (mLock) { 557 throwIfDestroyedLocked(); 558 unbindLocked(); 559 mDestroyed = true; 560 mCanUnbind = false; 561 } 562 } 563 564 public void dump(FileDescriptor fd, PrintWriter pw, String prefix) { 565 synchronized (mLock) { 566 pw.append(prefix).append("destroyed=") 567 .append(String.valueOf(mDestroyed)).println(); 568 pw.append(prefix).append("bound=") 569 .append((mRemoteInstance != null) ? "true" : "false").println(); 570 571 pw.flush(); 572 573 try { 574 getRemoteInstanceLazy().asBinder().dump(fd, new String[]{prefix}); 575 } catch (TimeoutException te) { 576 /* ignore */ 577 } catch (RemoteException re) { 578 /* ignore */ 579 } 580 } 581 } 582 583 private void onAllPrintJobsHandled() { 584 synchronized (mLock) { 585 throwIfDestroyedLocked(); 586 unbindLocked(); 587 } 588 } 589 590 private void onPrintJobStateChanged(PrintJobInfo printJob) { 591 mCallbacks.onPrintJobStateChanged(printJob); 592 } 593 594 private IPrintSpooler getRemoteInstanceLazy() throws TimeoutException { 595 synchronized (mLock) { 596 if (mRemoteInstance != null) { 597 return mRemoteInstance; 598 } 599 bindLocked(); 600 return mRemoteInstance; 601 } 602 } 603 604 private void bindLocked() throws TimeoutException { 605 if (mRemoteInstance != null) { 606 return; 607 } 608 if (DEBUG) { 609 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] bindLocked() " + 610 (mIsLowPriority ? "low priority" : "")); 611 } 612 613 int flags; 614 if (mIsLowPriority) { 615 flags = Context.BIND_AUTO_CREATE; 616 } else { 617 flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE; 618 } 619 620 mContext.bindServiceAsUser(mIntent, mServiceConnection, flags, mUserHandle); 621 622 final long startMillis = SystemClock.uptimeMillis(); 623 while (true) { 624 if (mRemoteInstance != null) { 625 break; 626 } 627 final long elapsedMillis = SystemClock.uptimeMillis() - startMillis; 628 final long remainingMillis = BIND_SPOOLER_SERVICE_TIMEOUT - elapsedMillis; 629 if (remainingMillis <= 0) { 630 throw new TimeoutException("Cannot get spooler!"); 631 } 632 try { 633 mLock.wait(remainingMillis); 634 } catch (InterruptedException ie) { 635 /* ignore */ 636 } 637 } 638 639 mCanUnbind = true; 640 mLock.notifyAll(); 641 } 642 643 private void unbindLocked() { 644 if (mRemoteInstance == null) { 645 return; 646 } 647 while (true) { 648 if (mCanUnbind) { 649 if (DEBUG) { 650 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] unbindLocked()"); 651 } 652 clearClientLocked(); 653 mRemoteInstance = null; 654 mContext.unbindService(mServiceConnection); 655 return; 656 } 657 try { 658 mLock.wait(); 659 } catch (InterruptedException ie) { 660 /* ignore */ 661 } 662 } 663 664 } 665 666 private void setClientLocked() { 667 try { 668 mRemoteInstance.setClient(mClient); 669 } catch (RemoteException re) { 670 Slog.d(LOG_TAG, "Error setting print spooler client", re); 671 } 672 } 673 674 private void clearClientLocked() { 675 try { 676 mRemoteInstance.setClient(null); 677 } catch (RemoteException re) { 678 Slog.d(LOG_TAG, "Error clearing print spooler client", re); 679 } 680 681 } 682 683 private void throwIfDestroyedLocked() { 684 if (mDestroyed) { 685 throw new IllegalStateException("Cannot interact with a destroyed instance."); 686 } 687 } 688 689 private void throwIfCalledOnMainThread() { 690 if (Thread.currentThread() == mContext.getMainLooper().getThread()) { 691 throw new RuntimeException("Cannot invoke on the main thread"); 692 } 693 } 694 695 private final class MyServiceConnection implements ServiceConnection { 696 @Override 697 public void onServiceConnected(ComponentName name, IBinder service) { 698 synchronized (mLock) { 699 mRemoteInstance = IPrintSpooler.Stub.asInterface(service); 700 setClientLocked(); 701 mLock.notifyAll(); 702 } 703 } 704 705 @Override 706 public void onServiceDisconnected(ComponentName name) { 707 synchronized (mLock) { 708 clearClientLocked(); 709 mRemoteInstance = null; 710 } 711 } 712 } 713 714 private static final class GetPrintJobInfosCaller 715 extends TimedRemoteCaller<List<PrintJobInfo>> { 716 private final IPrintSpoolerCallbacks mCallback; 717 718 public GetPrintJobInfosCaller() { 719 super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); 720 mCallback = new BasePrintSpoolerServiceCallbacks() { 721 @Override 722 public void onGetPrintJobInfosResult(List<PrintJobInfo> printJobs, int sequence) { 723 onRemoteMethodResult(printJobs, sequence); 724 } 725 }; 726 } 727 728 public List<PrintJobInfo> getPrintJobInfos(IPrintSpooler target, 729 ComponentName componentName, int state, int appId) 730 throws RemoteException, TimeoutException { 731 final int sequence = onBeforeRemoteCall(); 732 target.getPrintJobInfos(mCallback, componentName, state, appId, sequence); 733 return getResultTimed(sequence); 734 } 735 } 736 737 private static final class GetPrintJobInfoCaller extends TimedRemoteCaller<PrintJobInfo> { 738 private final IPrintSpoolerCallbacks mCallback; 739 740 public GetPrintJobInfoCaller() { 741 super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); 742 mCallback = new BasePrintSpoolerServiceCallbacks() { 743 @Override 744 public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) { 745 onRemoteMethodResult(printJob, sequence); 746 } 747 }; 748 } 749 750 public PrintJobInfo getPrintJobInfo(IPrintSpooler target, PrintJobId printJobId, 751 int appId) throws RemoteException, TimeoutException { 752 final int sequence = onBeforeRemoteCall(); 753 target.getPrintJobInfo(printJobId, mCallback, appId, sequence); 754 return getResultTimed(sequence); 755 } 756 } 757 758 private static final class SetPrintJobStateCaller extends TimedRemoteCaller<Boolean> { 759 private final IPrintSpoolerCallbacks mCallback; 760 761 public SetPrintJobStateCaller() { 762 super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); 763 mCallback = new BasePrintSpoolerServiceCallbacks() { 764 @Override 765 public void onSetPrintJobStateResult(boolean success, int sequence) { 766 onRemoteMethodResult(success, sequence); 767 } 768 }; 769 } 770 771 public boolean setPrintJobState(IPrintSpooler target, PrintJobId printJobId, 772 int status, String error) throws RemoteException, TimeoutException { 773 final int sequence = onBeforeRemoteCall(); 774 target.setPrintJobState(printJobId, status, error, mCallback, sequence); 775 return getResultTimed(sequence); 776 } 777 } 778 779 private static final class SetPrintJobTagCaller extends TimedRemoteCaller<Boolean> { 780 private final IPrintSpoolerCallbacks mCallback; 781 782 public SetPrintJobTagCaller() { 783 super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); 784 mCallback = new BasePrintSpoolerServiceCallbacks() { 785 @Override 786 public void onSetPrintJobTagResult(boolean success, int sequence) { 787 onRemoteMethodResult(success, sequence); 788 } 789 }; 790 } 791 792 public boolean setPrintJobTag(IPrintSpooler target, PrintJobId printJobId, 793 String tag) throws RemoteException, TimeoutException { 794 final int sequence = onBeforeRemoteCall(); 795 target.setPrintJobTag(printJobId, tag, mCallback, sequence); 796 return getResultTimed(sequence); 797 } 798 } 799 800 private static final class OnCustomPrinterIconLoadedCaller extends TimedRemoteCaller<Void> { 801 private final IPrintSpoolerCallbacks mCallback; 802 803 public OnCustomPrinterIconLoadedCaller() { 804 super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); 805 mCallback = new BasePrintSpoolerServiceCallbacks() { 806 @Override 807 public void onCustomPrinterIconCached(int sequence) { 808 onRemoteMethodResult(null, sequence); 809 } 810 }; 811 } 812 813 public Void onCustomPrinterIconLoaded(IPrintSpooler target, PrinterId printerId, 814 Icon icon) throws RemoteException, TimeoutException { 815 final int sequence = onBeforeRemoteCall(); 816 target.onCustomPrinterIconLoaded(printerId, icon, mCallback, sequence); 817 return getResultTimed(sequence); 818 } 819 } 820 821 private static final class ClearCustomPrinterIconCacheCaller extends TimedRemoteCaller<Void> { 822 private final IPrintSpoolerCallbacks mCallback; 823 824 public ClearCustomPrinterIconCacheCaller() { 825 super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); 826 mCallback = new BasePrintSpoolerServiceCallbacks() { 827 @Override 828 public void customPrinterIconCacheCleared(int sequence) { 829 onRemoteMethodResult(null, sequence); 830 } 831 }; 832 } 833 834 public Void clearCustomPrinterIconCache(IPrintSpooler target) 835 throws RemoteException, TimeoutException { 836 final int sequence = onBeforeRemoteCall(); 837 target.clearCustomPrinterIconCache(mCallback, sequence); 838 return getResultTimed(sequence); 839 } 840 } 841 842 private static final class GetCustomPrinterIconCaller extends TimedRemoteCaller<Icon> { 843 private final IPrintSpoolerCallbacks mCallback; 844 845 public GetCustomPrinterIconCaller() { 846 super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); 847 mCallback = new BasePrintSpoolerServiceCallbacks() { 848 @Override 849 public void onGetCustomPrinterIconResult(Icon icon, int sequence) { 850 onRemoteMethodResult(icon, sequence); 851 } 852 }; 853 } 854 855 public Icon getCustomPrinterIcon(IPrintSpooler target, PrinterId printerId) 856 throws RemoteException, TimeoutException { 857 final int sequence = onBeforeRemoteCall(); 858 target.getCustomPrinterIcon(printerId, mCallback, sequence); 859 return getResultTimed(sequence); 860 } 861 } 862 863 private static abstract class BasePrintSpoolerServiceCallbacks 864 extends IPrintSpoolerCallbacks.Stub { 865 @Override 866 public void onGetPrintJobInfosResult(List<PrintJobInfo> printJobIds, int sequence) { 867 /* do nothing */ 868 } 869 870 @Override 871 public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) { 872 /* do nothing */ 873 } 874 875 @Override 876 public void onCancelPrintJobResult(boolean canceled, int sequence) { 877 /* do nothing */ 878 } 879 880 @Override 881 public void onSetPrintJobStateResult(boolean success, int sequece) { 882 /* do nothing */ 883 } 884 885 @Override 886 public void onSetPrintJobTagResult(boolean success, int sequence) { 887 /* do nothing */ 888 } 889 890 @Override 891 public void onCustomPrinterIconCached(int sequence) { 892 /* do nothing */ 893 } 894 895 @Override 896 public void onGetCustomPrinterIconResult(@Nullable Icon icon, int sequence) { 897 /* do nothing */ 898 } 899 900 @Override 901 public void customPrinterIconCacheCleared(int sequence) { 902 /* do nothing */ 903 } 904 } 905 906 private static final class PrintSpoolerClient extends IPrintSpoolerClient.Stub { 907 908 private final WeakReference<RemotePrintSpooler> mWeakSpooler; 909 910 public PrintSpoolerClient(RemotePrintSpooler spooler) { 911 mWeakSpooler = new WeakReference<RemotePrintSpooler>(spooler); 912 } 913 914 @Override 915 public void onPrintJobQueued(PrintJobInfo printJob) { 916 RemotePrintSpooler spooler = mWeakSpooler.get(); 917 if (spooler != null) { 918 final long identity = Binder.clearCallingIdentity(); 919 try { 920 spooler.mCallbacks.onPrintJobQueued(printJob); 921 } finally { 922 Binder.restoreCallingIdentity(identity); 923 } 924 } 925 } 926 927 @Override 928 public void onAllPrintJobsForServiceHandled(ComponentName printService) { 929 RemotePrintSpooler spooler = mWeakSpooler.get(); 930 if (spooler != null) { 931 final long identity = Binder.clearCallingIdentity(); 932 try { 933 spooler.mCallbacks.onAllPrintJobsForServiceHandled(printService); 934 } finally { 935 Binder.restoreCallingIdentity(identity); 936 } 937 } 938 } 939 940 @Override 941 public void onAllPrintJobsHandled() { 942 RemotePrintSpooler spooler = mWeakSpooler.get(); 943 if (spooler != null) { 944 final long identity = Binder.clearCallingIdentity(); 945 try { 946 spooler.onAllPrintJobsHandled(); 947 } finally { 948 Binder.restoreCallingIdentity(identity); 949 } 950 } 951 } 952 953 @Override 954 public void onPrintJobStateChanged(PrintJobInfo printJob) { 955 RemotePrintSpooler spooler = mWeakSpooler.get(); 956 if (spooler != null) { 957 final long identity = Binder.clearCallingIdentity(); 958 try { 959 spooler.onPrintJobStateChanged(printJob); 960 } finally { 961 Binder.restoreCallingIdentity(identity); 962 } 963 } 964 } 965 } 966 } 967