PrintManager.java revision 53f57d162b0553102fbd5c4ccdda87dbfce5b763
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 * Creates a new instance. 74 * 75 * @param context The current context in which to operate. 76 * @param service The backing system service. 77 * 78 * @hide 79 */ 80 public PrintManager(Context context, IPrintManager service, int userId, int appId) { 81 mContext = context; 82 mService = service; 83 mUserId = userId; 84 mAppId = appId; 85 mPrintClient = new PrintClient(this); 86 mHandler = new Handler(context.getMainLooper(), null, false) { 87 @Override 88 public void handleMessage(Message message) { 89 SomeArgs args = (SomeArgs) message.obj; 90 Context context = (Context) args.arg1; 91 IntentSender intent = (IntentSender) args.arg2; 92 args.recycle(); 93 try { 94 context.startIntentSender(intent, null, 0, 0, 0); 95 } catch (SendIntentException sie) { 96 Log.e(LOG_TAG, "Couldn't start print job config activity.", sie); 97 } 98 } 99 }; 100 } 101 102 /** 103 * Creates an instance that can access all print jobs. 104 * 105 * @param userId The user id for which to get all print jobs. 106 * @return An instance of the caller has the permission to access 107 * all print jobs, null otherwise. 108 * 109 * @hide 110 */ 111 public PrintManager getGlobalPrintManagerForUser(int userId) { 112 return new PrintManager(mContext, mService, userId, APP_ID_ANY); 113 } 114 115 PrintJobInfo getPrintJob(int printJobId) { 116 try { 117 return mService.getPrintJob(printJobId, mAppId, mUserId); 118 } catch (RemoteException re) { 119 Log.e(LOG_TAG, "Error getting print job:" + printJobId, re); 120 } 121 return null; 122 } 123 124 /** 125 * Gets the print jobs for this application. 126 * 127 * @return The print job list. 128 * 129 * @see PrintJob 130 */ 131 public List<PrintJob> getPrintJobs() { 132 try { 133 List<PrintJobInfo> printJobInfos = mService.getPrintJobs(mAppId, mUserId); 134 if (printJobInfos == null) { 135 return Collections.emptyList(); 136 } 137 final int printJobCount = printJobInfos.size(); 138 List<PrintJob> printJobs = new ArrayList<PrintJob>(printJobCount); 139 for (int i = 0; i < printJobCount; i++) { 140 printJobs.add(new PrintJob(printJobInfos.get(i), this)); 141 } 142 return printJobs; 143 } catch (RemoteException re) { 144 Log.e(LOG_TAG, "Error getting print jobs!", re); 145 } 146 return Collections.emptyList(); 147 } 148 149 ICancellationSignal cancelPrintJob(int printJobId) { 150 try { 151 mService.cancelPrintJob(printJobId, mAppId, mUserId); 152 } catch (RemoteException re) { 153 Log.e(LOG_TAG, "Error cancleing a print job:" + printJobId, re); 154 } 155 return null; 156 } 157 158 /** 159 * Creates a print job for printing a file with default print attributes. 160 * 161 * @param printJobName A name for the new print job. 162 * @param pdfFile The PDF file to print. 163 * @param attributes The default print job attributes. 164 * @return The created print job. 165 */ 166 public PrintJob print(String printJobName, File pdfFile, PrintAttributes attributes) { 167 PrintFileAdapter printable = new PrintFileAdapter(pdfFile); 168 return print(printJobName, printable, attributes); 169 } 170 171 /** 172 * Creates a print job for printing a {@link PrintAdapter} with default print 173 * attributes. 174 * 175 * @param printJobName A name for the new print job. 176 * @param printAdapter The printable adapter to print. 177 * @param attributes The default print job attributes. 178 * @return The created print job. 179 */ 180 public PrintJob print(String printJobName, PrintAdapter printAdapter, 181 PrintAttributes attributes) { 182 PrintAdapterDelegate delegate = new PrintAdapterDelegate(printAdapter, 183 mContext.getMainLooper()); 184 try { 185 PrintJobInfo printJob = mService.print(printJobName, mPrintClient, delegate, 186 attributes, mAppId, mUserId); 187 if (printJob != null) { 188 return new PrintJob(printJob, this); 189 } 190 } catch (RemoteException re) { 191 Log.e(LOG_TAG, "Error creating a print job", re); 192 } 193 return null; 194 } 195 196 private static final class PrintClient extends IPrintClient.Stub { 197 198 private final WeakReference<PrintManager> mWeakPrintManager; 199 200 public PrintClient(PrintManager manager) { 201 mWeakPrintManager = new WeakReference<PrintManager>(manager); 202 } 203 204 @Override 205 public void startPrintJobConfigActivity(IntentSender intent) { 206 PrintManager manager = mWeakPrintManager.get(); 207 if (manager != null) { 208 SomeArgs args = SomeArgs.obtain(); 209 args.arg1 = manager.mContext; 210 args.arg2 = intent; 211 manager.mHandler.obtainMessage(0, args).sendToTarget(); 212 } 213 } 214 } 215 216 private static final class PrintAdapterDelegate extends IPrintAdapter.Stub { 217 private final Object mLock = new Object(); 218 219 private PrintAdapter mPrintAdapter; 220 221 private Handler mHandler; 222 223 public PrintAdapterDelegate(PrintAdapter printAdapter, Looper looper) { 224 mPrintAdapter = printAdapter; 225 mHandler = new MyHandler(looper); 226 } 227 228 @Override 229 public void start() { 230 synchronized (mLock) { 231 if (isFinishedLocked()) { 232 return; 233 } 234 mHandler.obtainMessage(MyHandler.MESSAGE_START, 235 mPrintAdapter).sendToTarget(); 236 } 237 } 238 239 @Override 240 public void printAttributesChanged(PrintAttributes attributes) { 241 synchronized (mLock) { 242 if (isFinishedLocked()) { 243 return; 244 } 245 SomeArgs args = SomeArgs.obtain(); 246 args.arg1 = mPrintAdapter; 247 args.arg2 = attributes; 248 mHandler.obtainMessage(MyHandler.MESSAGE_PRINT_ATTRIBUTES_CHANGED, 249 args).sendToTarget(); 250 } 251 } 252 253 @Override 254 public void print(List<PageRange> pages, ParcelFileDescriptor fd, 255 IPrintProgressListener progressListener) { 256 synchronized (mLock) { 257 if (isFinishedLocked()) { 258 return; 259 } 260 SomeArgs args = SomeArgs.obtain(); 261 args.arg1 = mPrintAdapter; 262 args.arg2 = pages; 263 args.arg3 = fd.getFileDescriptor(); 264 args.arg4 = progressListener; 265 mHandler.obtainMessage(MyHandler.MESSAGE_PRINT, args).sendToTarget(); 266 } 267 } 268 269 @Override 270 public void finish() { 271 synchronized (mLock) { 272 if (isFinishedLocked()) { 273 return; 274 } 275 mHandler.obtainMessage(MyHandler.MESSAGE_FINIS, 276 mPrintAdapter).sendToTarget(); 277 } 278 } 279 280 private boolean isFinishedLocked() { 281 return mPrintAdapter == null; 282 } 283 284 private void finishLocked() { 285 mPrintAdapter = null; 286 mHandler = null; 287 } 288 289 private final class MyHandler extends Handler { 290 public static final int MESSAGE_START = 1; 291 public static final int MESSAGE_PRINT_ATTRIBUTES_CHANGED = 2; 292 public static final int MESSAGE_PRINT = 3; 293 public static final int MESSAGE_FINIS = 4; 294 295 public MyHandler(Looper looper) { 296 super(looper, null, true); 297 } 298 299 @Override 300 public void handleMessage(Message message) { 301 switch (message.what) { 302 case MESSAGE_START: { 303 PrintAdapter adapter = (PrintAdapter) message.obj; 304 adapter.onStart(); 305 } break; 306 307 case MESSAGE_PRINT_ATTRIBUTES_CHANGED: { 308 SomeArgs args = (SomeArgs) message.obj; 309 PrintAdapter adapter = (PrintAdapter) args.arg1; 310 PrintAttributes attributes = (PrintAttributes) args.arg2; 311 args.recycle(); 312 adapter.onPrintAttributesChanged(attributes); 313 } break; 314 315 case MESSAGE_PRINT: { 316 SomeArgs args = (SomeArgs) message.obj; 317 PrintAdapter adapter = (PrintAdapter) args.arg1; 318 @SuppressWarnings("unchecked") 319 List<PageRange> pages = (List<PageRange>) args.arg2; 320 final FileDescriptor fd = (FileDescriptor) args.arg3; 321 IPrintProgressListener listener = (IPrintProgressListener) args.arg4; 322 args.recycle(); 323 try { 324 ICancellationSignal remoteSignal = CancellationSignal.createTransport(); 325 listener.onWriteStarted(adapter.getInfo(), remoteSignal); 326 327 CancellationSignal localSignal = CancellationSignal.fromTransport( 328 remoteSignal); 329 adapter.onPrint(pages, fd, localSignal, 330 new PrintProgressListenerWrapper(listener) { 331 @Override 332 public void onPrintFinished(List<PageRange> pages) { 333 IoUtils.closeQuietly(fd); 334 super.onPrintFinished(pages); 335 } 336 337 @Override 338 public void onPrintFailed(CharSequence error) { 339 IoUtils.closeQuietly(fd); 340 super.onPrintFailed(error); 341 } 342 }); 343 } catch (RemoteException re) { 344 Log.e(LOG_TAG, "Error printing", re); 345 IoUtils.closeQuietly(fd); 346 } 347 } break; 348 349 case MESSAGE_FINIS: { 350 PrintAdapter adapter = (PrintAdapter) message.obj; 351 adapter.onFinish(); 352 synchronized (mLock) { 353 finishLocked(); 354 } 355 } break; 356 357 default: { 358 throw new IllegalArgumentException("Unknown message: " 359 + message.what); 360 } 361 } 362 } 363 } 364 } 365 366 private static abstract class PrintProgressListenerWrapper extends PrintProgressCallback { 367 368 private final IPrintProgressListener mWrappedListener; 369 370 public PrintProgressListenerWrapper(IPrintProgressListener listener) { 371 mWrappedListener = listener; 372 } 373 374 @Override 375 public void onPrintFinished(List<PageRange> pages) { 376 try { 377 mWrappedListener.onWriteFinished(pages); 378 } catch (RemoteException re) { 379 Log.e(LOG_TAG, "Error calling onWriteFinished", re); 380 } 381 } 382 383 @Override 384 public void onPrintFailed(CharSequence error) { 385 try { 386 mWrappedListener.onWriteFailed(error); 387 } catch (RemoteException re) { 388 Log.e(LOG_TAG, "Error calling onWriteFailed", re); 389 } 390 } 391 } 392} 393