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