PrintManager.java revision 4b9a4d16872bbb50712e007b419ac0b35ff1582d
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.print; 18 19import android.content.Context; 20import android.content.IntentSender; 21import android.content.IntentSender.SendIntentException; 22import android.os.CancellationSignal; 23import android.os.Handler; 24import android.os.ICancellationSignal; 25import android.os.Looper; 26import android.os.Message; 27import android.os.ParcelFileDescriptor; 28import android.os.RemoteException; 29import android.print.PrintAdapter.PrintProgressCallback; 30import android.util.Log; 31 32import com.android.internal.os.SomeArgs; 33 34import libcore.io.IoUtils; 35 36import java.io.File; 37import java.io.FileDescriptor; 38import java.lang.ref.WeakReference; 39import java.util.ArrayList; 40import java.util.Collections; 41import java.util.List; 42 43/** 44 * System level service for accessing the printing capabilities of the platform. 45 * <p> 46 * To obtain a handle to the print manager do the following: 47 * </p> 48 * <pre> 49 * PrintManager printManager = 50 * (PrintManager) context.getSystemService(Context.PRINT_SERVICE); 51 * </pre> 52 */ 53public final class PrintManager { 54 55 private static final String LOG_TAG = "PrintManager"; 56 57 /** @hide */ 58 public static final int APP_ID_ANY = -2; 59 60 private final Context mContext; 61 62 private final IPrintManager mService; 63 64 private final int mUserId; 65 66 private final int mAppId; 67 68 private final PrintClient mPrintClient; 69 70 private final Handler mHandler; 71 72 /** 73 * Listener for the state of a print job. 74 */ 75 public static interface PrintJobStateListener { 76 public void onStateChanged(int state); 77 } 78 79 /** 80 * Creates a new instance. 81 * 82 * @param context The current context in which to operate. 83 * @param service The backing system service. 84 * 85 * @hide 86 */ 87 public PrintManager(Context context, IPrintManager service, int userId, int appId) { 88 mContext = context; 89 mService = service; 90 mUserId = userId; 91 mAppId = appId; 92 mPrintClient = new PrintClient(this); 93 mHandler = new Handler(context.getMainLooper(), null, false) { 94 @Override 95 public void handleMessage(Message message) { 96 SomeArgs args = (SomeArgs) message.obj; 97 Context context = (Context) args.arg1; 98 IntentSender intent = (IntentSender) args.arg2; 99 args.recycle(); 100 try { 101 context.startIntentSender(intent, null, 0, 0, 0); 102 } catch (SendIntentException sie) { 103 Log.e(LOG_TAG, "Couldn't start print job config activity.", sie); 104 } 105 } 106 }; 107 } 108 109 /** 110 * Creates an instance that can access all print jobs. 111 * 112 * @param userId The user id for which to get all print jobs. 113 * @return An instance of the caller has the permission to access 114 * all print jobs, null otherwise. 115 * 116 * @hide 117 */ 118 public PrintManager getGlobalPrintManagerForUser(int userId) { 119 return new PrintManager(mContext, mService, userId, APP_ID_ANY); 120 } 121 122 PrintJobInfo getPrintJob(int printJobId) { 123 try { 124 return mService.getPrintJob(printJobId, mAppId, mUserId); 125 } catch (RemoteException re) { 126 Log.e(LOG_TAG, "Error getting print job:" + printJobId, re); 127 } 128 return null; 129 } 130 131 /** 132 * Gets the print jobs for this application. 133 * 134 * @return The print job list. 135 * 136 * @see PrintJob 137 */ 138 public List<PrintJob> getPrintJobs() { 139 try { 140 List<PrintJobInfo> printJobInfos = mService.getPrintJobs(mAppId, mUserId); 141 if (printJobInfos == null) { 142 return Collections.emptyList(); 143 } 144 final int printJobCount = printJobInfos.size(); 145 List<PrintJob> printJobs = new ArrayList<PrintJob>(printJobCount); 146 for (int i = 0; i < printJobCount; i++) { 147 printJobs.add(new PrintJob(printJobInfos.get(i), this)); 148 } 149 return printJobs; 150 } catch (RemoteException re) { 151 Log.e(LOG_TAG, "Error getting print jobs!", re); 152 } 153 return Collections.emptyList(); 154 } 155 156 ICancellationSignal cancelPrintJob(int printJobId) { 157 try { 158 mService.cancelPrintJob(printJobId, mAppId, mUserId); 159 } catch (RemoteException re) { 160 Log.e(LOG_TAG, "Error cancleing a print job:" + printJobId, re); 161 } 162 return null; 163 } 164 165 /** 166 * Creates a print job for printing a file with default print attributes. 167 * 168 * @param printJobName A name for the new print job. 169 * @param pdfFile The PDF file to print. 170 * @param attributes The default print job attributes. 171 * @return The created print job. 172 */ 173 public PrintJob print(String printJobName, File pdfFile, PrintAttributes attributes) { 174 PrintFileAdapter printable = new PrintFileAdapter(pdfFile); 175 return print(printJobName, printable, attributes); 176 } 177 178 /** 179 * Creates a print job for printing a {@link PrintAdapter} with default print 180 * attributes. 181 * 182 * @param printJobName A name for the new print job. 183 * @param printAdapter The printable adapter to print. 184 * @param attributes The default print job attributes. 185 * @return The created print job. 186 */ 187 public PrintJob print(String printJobName, PrintAdapter printAdapter, 188 PrintAttributes attributes) { 189 PrintAdapterDelegate delegate = new PrintAdapterDelegate(printAdapter, 190 mContext.getMainLooper()); 191 try { 192 PrintJobInfo printJob = mService.print(printJobName, mPrintClient, delegate, 193 attributes, mAppId, mUserId); 194 if (printJob != null) { 195 return new PrintJob(printJob, this); 196 } 197 } catch (RemoteException re) { 198 Log.e(LOG_TAG, "Error creating a print job", re); 199 } 200 return null; 201 } 202 203 private static final class PrintClient extends IPrintClient.Stub { 204 205 private final WeakReference<PrintManager> mWeakPrintManager; 206 207 public PrintClient(PrintManager manager) { 208 mWeakPrintManager = new WeakReference<PrintManager>(manager); 209 } 210 211 @Override 212 public void startPrintJobConfigActivity(IntentSender intent) { 213 PrintManager manager = mWeakPrintManager.get(); 214 if (manager != null) { 215 SomeArgs args = SomeArgs.obtain(); 216 args.arg1 = manager.mContext; 217 args.arg2 = intent; 218 manager.mHandler.obtainMessage(0, args).sendToTarget(); 219 } 220 } 221 } 222 223 private static final class PrintAdapterDelegate extends IPrintAdapter.Stub { 224 private final Object mLock = new Object(); 225 226 private PrintAdapter mPrintAdapter; 227 228 private Handler mHandler; 229 230 public PrintAdapterDelegate(PrintAdapter printAdapter, Looper looper) { 231 mPrintAdapter = printAdapter; 232 mHandler = new MyHandler(looper); 233 } 234 235 @Override 236 public void start() { 237 synchronized (mLock) { 238 if (isFinishedLocked()) { 239 return; 240 } 241 mHandler.obtainMessage(MyHandler.MESSAGE_START, 242 mPrintAdapter).sendToTarget(); 243 } 244 } 245 246 @Override 247 public void printAttributesChanged(PrintAttributes attributes) { 248 synchronized (mLock) { 249 if (isFinishedLocked()) { 250 return; 251 } 252 SomeArgs args = SomeArgs.obtain(); 253 args.arg1 = mPrintAdapter; 254 args.arg2 = attributes; 255 mHandler.obtainMessage(MyHandler.MESSAGE_PRINT_ATTRIBUTES_CHANGED, 256 args).sendToTarget(); 257 } 258 } 259 260 @Override 261 public void print(List<PageRange> pages, ParcelFileDescriptor fd, 262 IPrintProgressListener progressListener) { 263 synchronized (mLock) { 264 if (isFinishedLocked()) { 265 return; 266 } 267 SomeArgs args = SomeArgs.obtain(); 268 args.arg1 = mPrintAdapter; 269 args.arg2 = pages; 270 args.arg3 = fd.getFileDescriptor(); 271 args.arg4 = progressListener; 272 mHandler.obtainMessage(MyHandler.MESSAGE_PRINT, args).sendToTarget(); 273 } 274 } 275 276 @Override 277 public void finish() { 278 synchronized (mLock) { 279 if (isFinishedLocked()) { 280 return; 281 } 282 mHandler.obtainMessage(MyHandler.MESSAGE_FINIS, 283 mPrintAdapter).sendToTarget(); 284 } 285 } 286 287 private boolean isFinishedLocked() { 288 return mPrintAdapter == null; 289 } 290 291 private void finishLocked() { 292 mPrintAdapter = null; 293 mHandler = null; 294 } 295 296 private final class MyHandler extends Handler { 297 public static final int MESSAGE_START = 1; 298 public static final int MESSAGE_PRINT_ATTRIBUTES_CHANGED = 2; 299 public static final int MESSAGE_PRINT = 3; 300 public static final int MESSAGE_FINIS = 4; 301 302 public MyHandler(Looper looper) { 303 super(looper, null, true); 304 } 305 306 @Override 307 public void handleMessage(Message message) { 308 switch (message.what) { 309 case MESSAGE_START: { 310 PrintAdapter adapter = (PrintAdapter) message.obj; 311 adapter.onStart(); 312 } break; 313 314 case MESSAGE_PRINT_ATTRIBUTES_CHANGED: { 315 SomeArgs args = (SomeArgs) message.obj; 316 PrintAdapter adapter = (PrintAdapter) args.arg1; 317 PrintAttributes attributes = (PrintAttributes) args.arg2; 318 args.recycle(); 319 adapter.onPrintAttributesChanged(attributes); 320 } break; 321 322 case MESSAGE_PRINT: { 323 SomeArgs args = (SomeArgs) message.obj; 324 PrintAdapter adapter = (PrintAdapter) args.arg1; 325 @SuppressWarnings("unchecked") 326 List<PageRange> pages = (List<PageRange>) args.arg2; 327 final FileDescriptor fd = (FileDescriptor) args.arg3; 328 IPrintProgressListener listener = (IPrintProgressListener) args.arg4; 329 args.recycle(); 330 try { 331 ICancellationSignal remoteSignal = CancellationSignal.createTransport(); 332 listener.onWriteStarted(adapter.getInfo(), remoteSignal); 333 334 CancellationSignal localSignal = CancellationSignal.fromTransport( 335 remoteSignal); 336 adapter.onPrint(pages, fd, localSignal, 337 new PrintProgressListenerWrapper(listener) { 338 @Override 339 public void onPrintFinished(List<PageRange> pages) { 340 IoUtils.closeQuietly(fd); 341 super.onPrintFinished(pages); 342 } 343 344 @Override 345 public void onPrintFailed(CharSequence error) { 346 IoUtils.closeQuietly(fd); 347 super.onPrintFailed(error); 348 } 349 }); 350 } catch (RemoteException re) { 351 Log.e(LOG_TAG, "Error printing", re); 352 IoUtils.closeQuietly(fd); 353 } 354 } break; 355 356 case MESSAGE_FINIS: { 357 PrintAdapter adapter = (PrintAdapter) message.obj; 358 adapter.onFinish(); 359 synchronized (mLock) { 360 finishLocked(); 361 } 362 } break; 363 364 default: { 365 throw new IllegalArgumentException("Unknown message: " 366 + message.what); 367 } 368 } 369 } 370 } 371 } 372 373 private static abstract class PrintProgressListenerWrapper extends PrintProgressCallback { 374 375 private final IPrintProgressListener mWrappedListener; 376 377 public PrintProgressListenerWrapper(IPrintProgressListener listener) { 378 mWrappedListener = listener; 379 } 380 381 @Override 382 public void onPrintFinished(List<PageRange> pages) { 383 try { 384 mWrappedListener.onWriteFinished(pages); 385 } catch (RemoteException re) { 386 Log.e(LOG_TAG, "Error calling onWriteFinished", re); 387 } 388 } 389 390 @Override 391 public void onPrintFailed(CharSequence error) { 392 try { 393 mWrappedListener.onWriteFailed(error); 394 } catch (RemoteException re) { 395 Log.e(LOG_TAG, "Error calling onWriteFailed", re); 396 } 397 } 398 } 399} 400