PrintManager.java revision 88d199130d44c6bacb383a7757e782cf97483c68
14b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/*
24b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Copyright (C) 2013 The Android Open Source Project
34b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *
44b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License");
54b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * you may not use this file except in compliance with the License.
64b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * You may obtain a copy of the License at
74b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *
84b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *      http://www.apache.org/licenses/LICENSE-2.0
94b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *
104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Unless required by applicable law or agreed to in writing, software
114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS,
124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * See the License for the specific language governing permissions and
144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * limitations under the License.
154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */
164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovpackage android.print;
184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.Context;
204b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.IntentSender;
214b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.IntentSender.SendIntentException;
226283608e0bd40548742839f5a8b02f7e5c9c5c7cSvetoslavimport android.os.Bundle;
234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.CancellationSignal;
244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Handler;
254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.ICancellationSignal;
264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Looper;
274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Message;
284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.ParcelFileDescriptor;
294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.RemoteException;
30a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.PrintDocumentAdapter.LayoutResultCallback;
31a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.PrintDocumentAdapter.WriteResultCallback;
3288d199130d44c6bacb383a7757e782cf97483c68Svetoslav Ganovimport android.text.TextUtils;
334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.util.Log;
344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport com.android.internal.os.SomeArgs;
364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport libcore.io.IoUtils;
384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.File;
404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.FileDescriptor;
414b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.lang.ref.WeakReference;
424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.ArrayList;
434b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.Collections;
444b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.List;
454b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
464b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/**
474b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * System level service for accessing the printing capabilities of the platform.
484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <p>
494b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * To obtain a handle to the print manager do the following:
504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </p>
514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * <pre>
524b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * PrintManager printManager =
534b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *         (PrintManager) context.getSystemService(Context.PRINT_SERVICE);
544b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * </pre>
554b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */
564b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovpublic final class PrintManager {
574b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private static final String LOG_TAG = "PrintManager";
594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
604b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /** @hide */
614b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public static final int APP_ID_ANY = -2;
624b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
634b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private final Context mContext;
644b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
654b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private final IPrintManager mService;
664b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
674b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private final int mUserId;
684b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
694b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private final int mAppId;
704b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
714b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private final PrintClient mPrintClient;
724b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
734b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private final Handler mHandler;
744b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
754b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
764b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * Creates a new instance.
774b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
784b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @param context The current context in which to operate.
794b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @param service The backing system service.
804b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
814b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @hide
824b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
834b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public PrintManager(Context context, IPrintManager service, int userId, int appId) {
844b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mContext = context;
854b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mService = service;
864b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mUserId = userId;
874b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mAppId = appId;
884b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mPrintClient = new PrintClient(this);
894b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mHandler = new Handler(context.getMainLooper(), null, false) {
904b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
914b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            public void handleMessage(Message message) {
924b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                SomeArgs args = (SomeArgs) message.obj;
934b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                Context context = (Context) args.arg1;
944b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                IntentSender intent = (IntentSender) args.arg2;
954b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                args.recycle();
964b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                try {
974b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    context.startIntentSender(intent, null, 0, 0, 0);
984b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                } catch (SendIntentException sie) {
994b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    Log.e(LOG_TAG, "Couldn't start print job config activity.", sie);
1004b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                }
1014b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
1024b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        };
1034b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1044b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1054b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
1064b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * Creates an instance that can access all print jobs.
1074b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
1084b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @param userId The user id for which to get all print jobs.
109a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov     * @return An instance if the caller has the permission to access
1104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * all print jobs, null otherwise.
1114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
1124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @hide
1134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
1144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public PrintManager getGlobalPrintManagerForUser(int userId) {
1154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        return new PrintManager(mContext, mService, userId, APP_ID_ANY);
1164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
118a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    PrintJobInfo getPrintJobInfo(int printJobId) {
1194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        try {
120a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return mService.getPrintJobInfo(printJobId, mAppId, mUserId);
1214b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        } catch (RemoteException re) {
122a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Log.e(LOG_TAG, "Error getting a print job info:" + printJobId, re);
1234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
1244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        return null;
1254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
1284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * Gets the print jobs for this application.
1294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
1304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @return The print job list.
1314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
1324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @see PrintJob
1334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
1344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public List<PrintJob> getPrintJobs() {
1354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        try {
136a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            List<PrintJobInfo> printJobInfos = mService.getPrintJobInfos(mAppId, mUserId);
1374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            if (printJobInfos == null) {
1384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                return Collections.emptyList();
1394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
1404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            final int printJobCount = printJobInfos.size();
1414b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            List<PrintJob> printJobs = new ArrayList<PrintJob>(printJobCount);
1424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            for (int i = 0; i < printJobCount; i++) {
1434b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                printJobs.add(new PrintJob(printJobInfos.get(i), this));
1444b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
1454b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            return printJobs;
1464b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        } catch (RemoteException re) {
147a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Log.e(LOG_TAG, "Error getting print jobs", re);
1484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
1494b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        return Collections.emptyList();
1504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
152a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    void cancelPrintJob(int printJobId) {
1534b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        try {
1544b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            mService.cancelPrintJob(printJobId, mAppId, mUserId);
1554b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        } catch (RemoteException re) {
156a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            Log.e(LOG_TAG, "Error cancleing a print job: " + printJobId, re);
1574b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
1584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1604b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
1614b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * Creates a print job for printing a file with default print attributes.
1624b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
1634b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @param printJobName A name for the new print job.
1644b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @param pdfFile The PDF file to print.
1654b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @param attributes The default print job attributes.
1664b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @return The created print job.
167fd90651cfcc7e2b75254666fd6861038b72fb4acSvetoslav     *
168fd90651cfcc7e2b75254666fd6861038b72fb4acSvetoslav     * @see PrintJob
1694b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
1704b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public PrintJob print(String printJobName, File pdfFile, PrintAttributes attributes) {
17117b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        FileDocumentAdapter documentAdapter = new FileDocumentAdapter(mContext, pdfFile);
172a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return print(printJobName, documentAdapter, attributes);
1734b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1744b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1754b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
176a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov     * Creates a print job for printing a {@link PrintDocumentAdapter} with default print
1774b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * attributes.
1784b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     *
1794b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @param printJobName A name for the new print job.
180a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov     * @param documentAdapter An adapter that emits the document to print.
1814b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @param attributes The default print job attributes.
1824b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @return The created print job.
183fd90651cfcc7e2b75254666fd6861038b72fb4acSvetoslav     *
184fd90651cfcc7e2b75254666fd6861038b72fb4acSvetoslav     * @see PrintJob
1854b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
186a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter,
1874b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            PrintAttributes attributes) {
18888d199130d44c6bacb383a7757e782cf97483c68Svetoslav Ganov        if (TextUtils.isEmpty(printJobName)) {
18988d199130d44c6bacb383a7757e782cf97483c68Svetoslav Ganov            throw new IllegalArgumentException("priintJobName cannot be empty");
19088d199130d44c6bacb383a7757e782cf97483c68Svetoslav Ganov        }
191a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        PrintDocumentAdapterDelegate delegate = new PrintDocumentAdapterDelegate(documentAdapter,
1924b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                mContext.getMainLooper());
1934b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        try {
1944b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            PrintJobInfo printJob = mService.print(printJobName, mPrintClient, delegate,
1954b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    attributes, mAppId, mUserId);
1964b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            if (printJob != null) {
1974b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                return new PrintJob(printJob, this);
1984b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
1994b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        } catch (RemoteException re) {
2004b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            Log.e(LOG_TAG, "Error creating a print job", re);
2014b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
2024b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        return null;
2034b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
2044b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2054b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private static final class PrintClient extends IPrintClient.Stub {
2064b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2074b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        private final WeakReference<PrintManager> mWeakPrintManager;
2084b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2094b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        public PrintClient(PrintManager manager) {
2104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            mWeakPrintManager = new WeakReference<PrintManager>(manager);
2114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
2124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
2144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        public void startPrintJobConfigActivity(IntentSender intent)  {
2154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            PrintManager manager = mWeakPrintManager.get();
2164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            if (manager != null) {
2174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                SomeArgs args = SomeArgs.obtain();
2184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                args.arg1 =  manager.mContext;
2194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                args.arg2 = intent;
2204b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                manager.mHandler.obtainMessage(0, args).sendToTarget();
2214b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
2224b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
2234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
2244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
225a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub {
226a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK - cleared in finish()
2274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
228a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private Handler mHandler; // Strong reference OK - cleared in finish()
2294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
230a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public PrintDocumentAdapterDelegate(PrintDocumentAdapter documentAdapter, Looper looper) {
231a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mDocumentAdapter = documentAdapter;
2324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            mHandler = new MyHandler(looper);
2334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
2344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
2364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        public void start() {
237a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mHandler.sendEmptyMessage(MyHandler.MSG_START);
2384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
2394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
2416283608e0bd40548742839f5a8b02f7e5c9c5c7cSvetoslav        public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
2426283608e0bd40548742839f5a8b02f7e5c9c5c7cSvetoslav                ILayoutResultCallback callback, Bundle metadata) {
243a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            SomeArgs args = SomeArgs.obtain();
244a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            args.arg1 = oldAttributes;
245a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            args.arg2 = newAttributes;
246a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            args.arg3 = callback;
2476283608e0bd40548742839f5a8b02f7e5c9c5c7cSvetoslav            args.arg4 = metadata;
248a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mHandler.obtainMessage(MyHandler.MSG_LAYOUT, args).sendToTarget();
2494b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
2504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2514b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
252a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void write(List<PageRange> pages, ParcelFileDescriptor fd,
253a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            IWriteResultCallback callback) {
254a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            SomeArgs args = SomeArgs.obtain();
255a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            args.arg1 = pages;
256a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            args.arg2 = fd.getFileDescriptor();
257a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            args.arg3 = callback;
258a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mHandler.obtainMessage(MyHandler.MSG_WRITE, args).sendToTarget();
2594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
2604b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2614b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
2624b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        public void finish() {
263a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mHandler.sendEmptyMessage(MyHandler.MSG_FINISH);
2644b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
2654b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
266a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private boolean isFinished() {
267a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return mDocumentAdapter == null;
2684b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
2694b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
270a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private void doFinish() {
271a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mDocumentAdapter = null;
2724b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            mHandler = null;
2734b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
2744b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2754b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        private final class MyHandler extends Handler {
276a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            public static final int MSG_START = 1;
277a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            public static final int MSG_LAYOUT = 2;
278a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            public static final int MSG_WRITE = 3;
279a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            public static final int MSG_FINISH = 4;
2804b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2814b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            public MyHandler(Looper looper) {
2824b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                super(looper, null, true);
2834b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
2844b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2854b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
286a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            @SuppressWarnings("unchecked")
2874b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            public void handleMessage(Message message) {
288a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                if (isFinished()) {
289a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    return;
290a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
2914b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                switch (message.what) {
292a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    case MSG_START: {
293a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        mDocumentAdapter.onStart();
2944b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    } break;
2954b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
296a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    case MSG_LAYOUT: {
2974b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        SomeArgs args = (SomeArgs) message.obj;
298a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        PrintAttributes oldAttributes = (PrintAttributes) args.arg1;
299a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        PrintAttributes newAttributes = (PrintAttributes) args.arg2;
300a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        ILayoutResultCallback callback = (ILayoutResultCallback) args.arg3;
3016283608e0bd40548742839f5a8b02f7e5c9c5c7cSvetoslav                        Bundle metadata = (Bundle) args.arg4;
3024b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        args.recycle();
303a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
304a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        try {
305a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                            ICancellationSignal remoteSignal = CancellationSignal.createTransport();
306a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                            callback.onLayoutStarted(remoteSignal);
307a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
308a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                            mDocumentAdapter.onLayout(oldAttributes, newAttributes,
309a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                                    CancellationSignal.fromTransport(remoteSignal),
3106283608e0bd40548742839f5a8b02f7e5c9c5c7cSvetoslav                                    new LayoutResultCallbackWrapper(callback), metadata);
311a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        } catch (RemoteException re) {
312a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                            Log.e(LOG_TAG, "Error printing", re);
313a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        }
3144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    } break;
3154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
316a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    case MSG_WRITE: {
3174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        SomeArgs args = (SomeArgs) message.obj;
318a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        List<PageRange> pages = (List<PageRange>) args.arg1;
319a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        FileDescriptor fd = (FileDescriptor) args.arg2;
320a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        IWriteResultCallback callback = (IWriteResultCallback) args.arg3;
3214b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        args.recycle();
322a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
3234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        try {
3244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                            ICancellationSignal remoteSignal = CancellationSignal.createTransport();
325a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                            callback.onWriteStarted(remoteSignal);
326a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
327a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                            mDocumentAdapter.onWrite(pages, fd,
328a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                                    CancellationSignal.fromTransport(remoteSignal),
329a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                                    new WriteResultCallbackWrapper(callback, fd));
3304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        } catch (RemoteException re) {
3314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                            Log.e(LOG_TAG, "Error printing", re);
3324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                            IoUtils.closeQuietly(fd);
3334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        }
3344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    } break;
3354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
336a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    case MSG_FINISH: {
337a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        mDocumentAdapter.onFinish();
338a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        doFinish();
3394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    } break;
3404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
3414b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    default: {
3424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        throw new IllegalArgumentException("Unknown message: "
3434b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                                + message.what);
3444b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    }
3454b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                }
3464b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
3474b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
3484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
3494b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
350a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final class WriteResultCallbackWrapper extends WriteResultCallback {
351a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
352a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final IWriteResultCallback mWrappedCallback;
353a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final FileDescriptor mFd;
354a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
355a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public WriteResultCallbackWrapper(IWriteResultCallback callback,
356a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                FileDescriptor fd) {
357a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mWrappedCallback = callback;
358a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mFd = fd;
359a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
360a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
361a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
362a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onWriteFinished(List<PageRange> pages) {
363a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            try {
364a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                // Close before notifying the other end. We want
365a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                // to be ready by the time we announce it.
366a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                IoUtils.closeQuietly(mFd);
367a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                mWrappedCallback.onWriteFinished(pages);
368a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            } catch (RemoteException re) {
369a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                Log.e(LOG_TAG, "Error calling onWriteFinished", re);
370a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
371a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
372a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
373a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
374a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onWriteFailed(CharSequence error) {
375a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            try {
376a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                // Close before notifying the other end. We want
377a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                // to be ready by the time we announce it.
378a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                IoUtils.closeQuietly(mFd);
379a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                mWrappedCallback.onWriteFailed(error);
380a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            } catch (RemoteException re) {
381a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                Log.e(LOG_TAG, "Error calling onWriteFailed", re);
382a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
383a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
384a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
385a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
386a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private static final class LayoutResultCallbackWrapper extends LayoutResultCallback {
3874b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
388a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final ILayoutResultCallback mWrappedCallback;
3894b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
390a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public LayoutResultCallbackWrapper(ILayoutResultCallback callback) {
391fd90651cfcc7e2b75254666fd6861038b72fb4acSvetoslav            mWrappedCallback = callback;
3924b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
3934b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
3944b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
395a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
3964b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            try {
397a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                mWrappedCallback.onLayoutFinished(info, changed);
3984b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            } catch (RemoteException re) {
399a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                Log.e(LOG_TAG, "Error calling onLayoutFinished", re);
4004b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
4014b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
4024b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
4034b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
404a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public void onLayoutFailed(CharSequence error) {
4054b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            try {
406a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                mWrappedCallback.onLayoutFailed(error);
4074b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            } catch (RemoteException re) {
408a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                Log.e(LOG_TAG, "Error calling onLayoutFailed", re);
4094b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
4104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
4114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
4124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov}
413