blob: be9b59658c7bec63be67a8675070b19d18ed6e5c [file] [log] [blame]
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -07001/*
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;
Svetoslavfd906512013-06-24 09:04:48 -070029import android.print.PrintAdapter.PrintResultCallback;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070030import 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 /**
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070073 * 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.
Svetoslavfd906512013-06-24 09:04:48 -0700165 *
166 * @see PrintJob
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700167 */
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.
Svetoslavfd906512013-06-24 09:04:48 -0700181 *
182 * @see PrintJob
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700183 */
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,
Svetoslavfd906512013-06-24 09:04:48 -0700259 IPrintResultCallback callback) {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700260 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();
Svetoslavfd906512013-06-24 09:04:48 -0700268 args.arg4 = callback;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700269 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;
Svetoslavfd906512013-06-24 09:04:48 -0700325 IPrintResultCallback callback = (IPrintResultCallback) args.arg4;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700326 args.recycle();
327 try {
328 ICancellationSignal remoteSignal = CancellationSignal.createTransport();
Svetoslavfd906512013-06-24 09:04:48 -0700329 callback.onPrintStarted(adapter.getInfo(), remoteSignal);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700330
331 CancellationSignal localSignal = CancellationSignal.fromTransport(
332 remoteSignal);
333 adapter.onPrint(pages, fd, localSignal,
Svetoslavfd906512013-06-24 09:04:48 -0700334 new PrintResultCallbackWrapper(callback) {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700335 @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
Svetoslavfd906512013-06-24 09:04:48 -0700370 private static abstract class PrintResultCallbackWrapper extends PrintResultCallback {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700371
Svetoslavfd906512013-06-24 09:04:48 -0700372 private final IPrintResultCallback mWrappedCallback;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700373
Svetoslavfd906512013-06-24 09:04:48 -0700374 public PrintResultCallbackWrapper(IPrintResultCallback callback) {
375 mWrappedCallback = callback;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700376 }
377
378 @Override
379 public void onPrintFinished(List<PageRange> pages) {
380 try {
Svetoslavfd906512013-06-24 09:04:48 -0700381 mWrappedCallback.onPrintFinished(pages);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700382 } catch (RemoteException re) {
Svetoslavfd906512013-06-24 09:04:48 -0700383 Log.e(LOG_TAG, "Error calling onPrintFinished", re);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700384 }
385 }
386
387 @Override
388 public void onPrintFailed(CharSequence error) {
389 try {
Svetoslavfd906512013-06-24 09:04:48 -0700390 mWrappedCallback.onPrintFailed(error);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700391 } catch (RemoteException re) {
Svetoslavfd906512013-06-24 09:04:48 -0700392 Log.e(LOG_TAG, "Error calling onPrintFailed", re);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700393 }
394 }
395 }
396}