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
1917b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslavimport android.content.Context;
204b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.AsyncTask;
216283608e0bd40548742839f5a8b02f7e5c9c5c7cSvetoslavimport android.os.Bundle;
224b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.CancellationSignal;
234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.CancellationSignal.OnCancelListener;
24d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganovimport android.os.ParcelFileDescriptor;
254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.util.Log;
264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2717b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslavimport com.android.internal.R;
2817b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav
294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport libcore.io.IoUtils;
304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.File;
324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.FileInputStream;
334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.FileOutputStream;
344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.IOException;
354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.InputStream;
364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.OutputStream;
374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/**
3919fba5d34a444ce145ab0d3a12c578d9d5d3f38cSvetoslav Ganov * Adapter for printing PDF files. This class could be useful if you
40798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * want to print a file and intercept when the system is ready
4119fba5d34a444ce145ab0d3a12c578d9d5d3f38cSvetoslav Ganov * spooling the data, so you can delete the file if it is a
4219fba5d34a444ce145ab0d3a12c578d9d5d3f38cSvetoslav Ganov * temporary one. To achieve this one must override {@link #onFinish()}
4319fba5d34a444ce145ab0d3a12c578d9d5d3f38cSvetoslav Ganov * and delete the file yourself.
44b450d0d4d7fca16674fea02f15e21dc737352c40Svetoslav *
45b450d0d4d7fca16674fea02f15e21dc737352c40Svetoslav * @hide
464b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */
479abf735387329758ca310acad3baa70eee1dba42Svetoslavpublic class PrintFileDocumentAdapter extends PrintDocumentAdapter {
484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
491c8f1e06a609507533609b4e04161c1c4fcb2849Philip P. Moltmann    private static final String LOG_TAG = "PrintedFileDocAdapter";
504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
5117b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav    private final Context mContext;
5217b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav
534b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private final File mFile;
544b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
55798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    private final PrintDocumentInfo mDocumentInfo;
56798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov
574b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private WriteFileAsyncTask mWriteFileAsyncTask;
584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
59798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    /**
60798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * Constructor.
61798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     *
62798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @param context Context for accessing resources.
6319fba5d34a444ce145ab0d3a12c578d9d5d3f38cSvetoslav Ganov     * @param file The PDF file to print.
64798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @param documentInfo The information about the printed file.
65798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     */
66798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    public PrintFileDocumentAdapter(Context context, File file,
67798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov            PrintDocumentInfo documentInfo) {
684b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        if (file == null) {
694b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            throw new IllegalArgumentException("File cannot be null!");
704b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
71798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov        if (documentInfo == null) {
72798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov            throw new IllegalArgumentException("documentInfo cannot be null!");
73798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov        }
7417b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        mContext = context;
754b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mFile = file;
76798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov        mDocumentInfo = documentInfo;
774b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
784b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
794b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
80a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
816283608e0bd40548742839f5a8b02f7e5c9c5c7cSvetoslav            CancellationSignal cancellationSignal, LayoutResultCallback callback,
826283608e0bd40548742839f5a8b02f7e5c9c5c7cSvetoslav            Bundle metadata) {
83798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov        callback.onLayoutFinished(mDocumentInfo, false);
84a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
85a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
86a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    @Override
87d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    public void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
88a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            CancellationSignal cancellationSignal, WriteResultCallback callback) {
8917b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        mWriteFileAsyncTask = new WriteFileAsyncTask(destination, cancellationSignal, callback);
904b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mWriteFileAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
914b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                (Void[]) null);
924b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
934b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
9417b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav    private final class WriteFileAsyncTask extends AsyncTask<Void, Void, Void> {
954b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
96d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        private final ParcelFileDescriptor mDestination;
974b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
98a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final WriteResultCallback mResultCallback;
994b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1004b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        private final CancellationSignal mCancellationSignal;
1014b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
102d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public WriteFileAsyncTask(ParcelFileDescriptor destination,
103a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                CancellationSignal cancellationSignal, WriteResultCallback callback) {
1044b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            mDestination = destination;
105fd90651cfcc7e2b75254666fd6861038b72fb4acSvetoslav            mResultCallback = callback;
10617b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav            mCancellationSignal = cancellationSignal;
1074b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            mCancellationSignal.setOnCancelListener(new OnCancelListener() {
1084b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                @Override
1094b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                public void onCancel() {
1104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    cancel(true);
1114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                }
1124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            });
1134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
1144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
1164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        protected Void doInBackground(Void... params) {
1174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            InputStream in = null;
118d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            OutputStream out = new FileOutputStream(mDestination.getFileDescriptor());
1194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            final byte[] buffer = new byte[8192];
1204b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            try {
12117b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav                in = new FileInputStream(mFile);
1224b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                while (true) {
12317b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav                    if (isCancelled()) {
12417b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav                        break;
12517b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav                    }
1264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    final int readByteCount = in.read(buffer);
1274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    if (readByteCount < 0) {
1284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        break;
1294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    }
1304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    out.write(buffer, 0, readByteCount);
1314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                }
1324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov             } catch (IOException ioe) {
13317b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav                 Log.e(LOG_TAG, "Error writing data!", ioe);
13417b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav                 mResultCallback.onWriteFailed(mContext.getString(
13517b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav                         R.string.write_fail_reason_cannot_write));
1364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov             } finally {
1374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                IoUtils.closeQuietly(in);
1384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                IoUtils.closeQuietly(out);
1394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
1404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            return null;
1414b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
14217b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav
14317b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        @Override
14417b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        protected void onPostExecute(Void result) {
14585b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mResultCallback.onWriteFinished(new PageRange[] {PageRange.ALL_PAGES});
14617b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        }
14717b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav
14817b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        @Override
14917b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        protected void onCancelled(Void result) {
15017b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav            mResultCallback.onWriteFailed(mContext.getString(
15117b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav                    R.string.write_fail_reason_cancelled));
15217b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        }
1534b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1544b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov}
1554b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
156