PrintManager.java revision fd90651cfcc7e2b75254666fd6861038b72fb4ac
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.PrintResultCallback; 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 * @see PrintJob 167 */ 168 public PrintJob print(String printJobName, File pdfFile, PrintAttributes attributes) { 169 PrintFileAdapter printable = new PrintFileAdapter(pdfFile); 170 return print(printJobName, printable, attributes); 171 } 172 173 /** 174 * Creates a print job for printing a {@link PrintAdapter} with default print 175 * attributes. 176 * 177 * @param printJobName A name for the new print job. 178 * @param printAdapter The printable adapter to print. 179 * @param attributes The default print job attributes. 180 * @return The created print job. 181 * 182 * @see PrintJob 183 */ 184 public PrintJob print(String printJobName, PrintAdapter printAdapter, 185 PrintAttributes attributes) { 186 PrintAdapterDelegate delegate = new PrintAdapterDelegate(printAdapter, 187 mContext.getMainLooper()); 188 try { 189 PrintJobInfo printJob = mService.print(printJobName, mPrintClient, delegate, 190 attributes, mAppId, mUserId); 191 if (printJob != null) { 192 return new PrintJob(printJob, this); 193 } 194 } catch (RemoteException re) { 195 Log.e(LOG_TAG, "Error creating a print job", re); 196 } 197 return null; 198 } 199 200 private static final class PrintClient extends IPrintClient.Stub { 201 202 private final WeakReference<PrintManager> mWeakPrintManager; 203 204 public PrintClient(PrintManager manager) { 205 mWeakPrintManager = new WeakReference<PrintManager>(manager); 206 } 207 208 @Override 209 public void startPrintJobConfigActivity(IntentSender intent) { 210 PrintManager manager = mWeakPrintManager.get(); 211 if (manager != null) { 212 SomeArgs args = SomeArgs.obtain(); 213 args.arg1 = manager.mContext; 214 args.arg2 = intent; 215 manager.mHandler.obtainMessage(0, args).sendToTarget(); 216 } 217 } 218 } 219 220 private static final class PrintAdapterDelegate extends IPrintAdapter.Stub { 221 private final Object mLock = new Object(); 222 223 private PrintAdapter mPrintAdapter; 224 225 private Handler mHandler; 226 227 public PrintAdapterDelegate(PrintAdapter printAdapter, Looper looper) { 228 mPrintAdapter = printAdapter; 229 mHandler = new MyHandler(looper); 230 } 231 232 @Override 233 public void start() { 234 synchronized (mLock) { 235 if (isFinishedLocked()) { 236 return; 237 } 238 mHandler.obtainMessage(MyHandler.MESSAGE_START, 239 mPrintAdapter).sendToTarget(); 240 } 241 } 242 243 @Override 244 public void printAttributesChanged(PrintAttributes attributes) { 245 synchronized (mLock) { 246 if (isFinishedLocked()) { 247 return; 248 } 249 SomeArgs args = SomeArgs.obtain(); 250 args.arg1 = mPrintAdapter; 251 args.arg2 = attributes; 252 mHandler.obtainMessage(MyHandler.MESSAGE_PRINT_ATTRIBUTES_CHANGED, 253 args).sendToTarget(); 254 } 255 } 256 257 @Override 258 public void print(List<PageRange> pages, ParcelFileDescriptor fd, 259 IPrintResultCallback callback) { 260 synchronized (mLock) { 261 if (isFinishedLocked()) { 262 return; 263 } 264 SomeArgs args = SomeArgs.obtain(); 265 args.arg1 = mPrintAdapter; 266 args.arg2 = pages; 267 args.arg3 = fd.getFileDescriptor(); 268 args.arg4 = callback; 269 mHandler.obtainMessage(MyHandler.MESSAGE_PRINT, args).sendToTarget(); 270 } 271 } 272 273 @Override 274 public void finish() { 275 synchronized (mLock) { 276 if (isFinishedLocked()) { 277 return; 278 } 279 mHandler.obtainMessage(MyHandler.MESSAGE_FINIS, 280 mPrintAdapter).sendToTarget(); 281 } 282 } 283 284 private boolean isFinishedLocked() { 285 return mPrintAdapter == null; 286 } 287 288 private void finishLocked() { 289 mPrintAdapter = null; 290 mHandler = null; 291 } 292 293 private final class MyHandler extends Handler { 294 public static final int MESSAGE_START = 1; 295 public static final int MESSAGE_PRINT_ATTRIBUTES_CHANGED = 2; 296 public static final int MESSAGE_PRINT = 3; 297 public static final int MESSAGE_FINIS = 4; 298 299 public MyHandler(Looper looper) { 300 super(looper, null, true); 301 } 302 303 @Override 304 public void handleMessage(Message message) { 305 switch (message.what) { 306 case MESSAGE_START: { 307 PrintAdapter adapter = (PrintAdapter) message.obj; 308 adapter.onStart(); 309 } break; 310 311 case MESSAGE_PRINT_ATTRIBUTES_CHANGED: { 312 SomeArgs args = (SomeArgs) message.obj; 313 PrintAdapter adapter = (PrintAdapter) args.arg1; 314 PrintAttributes attributes = (PrintAttributes) args.arg2; 315 args.recycle(); 316 adapter.onPrintAttributesChanged(attributes); 317 } break; 318 319 case MESSAGE_PRINT: { 320 SomeArgs args = (SomeArgs) message.obj; 321 PrintAdapter adapter = (PrintAdapter) args.arg1; 322 @SuppressWarnings("unchecked") 323 List<PageRange> pages = (List<PageRange>) args.arg2; 324 final FileDescriptor fd = (FileDescriptor) args.arg3; 325 IPrintResultCallback callback = (IPrintResultCallback) args.arg4; 326 args.recycle(); 327 try { 328 ICancellationSignal remoteSignal = CancellationSignal.createTransport(); 329 callback.onPrintStarted(adapter.getInfo(), remoteSignal); 330 331 CancellationSignal localSignal = CancellationSignal.fromTransport( 332 remoteSignal); 333 adapter.onPrint(pages, fd, localSignal, 334 new PrintResultCallbackWrapper(callback) { 335 @Override 336 public void onPrintFinished(List<PageRange> pages) { 337 IoUtils.closeQuietly(fd); 338 super.onPrintFinished(pages); 339 } 340 341 @Override 342 public void onPrintFailed(CharSequence error) { 343 IoUtils.closeQuietly(fd); 344 super.onPrintFailed(error); 345 } 346 }); 347 } catch (RemoteException re) { 348 Log.e(LOG_TAG, "Error printing", re); 349 IoUtils.closeQuietly(fd); 350 } 351 } break; 352 353 case MESSAGE_FINIS: { 354 PrintAdapter adapter = (PrintAdapter) message.obj; 355 adapter.onFinish(); 356 synchronized (mLock) { 357 finishLocked(); 358 } 359 } break; 360 361 default: { 362 throw new IllegalArgumentException("Unknown message: " 363 + message.what); 364 } 365 } 366 } 367 } 368 } 369 370 private static abstract class PrintResultCallbackWrapper extends PrintResultCallback { 371 372 private final IPrintResultCallback mWrappedCallback; 373 374 public PrintResultCallbackWrapper(IPrintResultCallback callback) { 375 mWrappedCallback = callback; 376 } 377 378 @Override 379 public void onPrintFinished(List<PageRange> pages) { 380 try { 381 mWrappedCallback.onPrintFinished(pages); 382 } catch (RemoteException re) { 383 Log.e(LOG_TAG, "Error calling onPrintFinished", re); 384 } 385 } 386 387 @Override 388 public void onPrintFailed(CharSequence error) { 389 try { 390 mWrappedCallback.onPrintFailed(error); 391 } catch (RemoteException re) { 392 Log.e(LOG_TAG, "Error calling onPrintFailed", re); 393 } 394 } 395 } 396} 397