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;
2445c97df89d6c9d8b5252ba9fc27c41e75c81254dJeff Sharkeyimport android.os.FileUtils;
2545c97df89d6c9d8b5252ba9fc27c41e75c81254dJeff Sharkeyimport android.os.OperationCanceledException;
26d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganovimport android.os.ParcelFileDescriptor;
274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.util.Log;
284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
2917b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslavimport com.android.internal.R;
3017b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav
314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport libcore.io.IoUtils;
324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.File;
344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.FileInputStream;
354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.FileOutputStream;
364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.IOException;
374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.InputStream;
384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.OutputStream;
394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/**
4119fba5d34a444ce145ab0d3a12c578d9d5d3f38cSvetoslav Ganov * Adapter for printing PDF files. This class could be useful if you
42798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov * want to print a file and intercept when the system is ready
4319fba5d34a444ce145ab0d3a12c578d9d5d3f38cSvetoslav Ganov * spooling the data, so you can delete the file if it is a
4419fba5d34a444ce145ab0d3a12c578d9d5d3f38cSvetoslav Ganov * temporary one. To achieve this one must override {@link #onFinish()}
4519fba5d34a444ce145ab0d3a12c578d9d5d3f38cSvetoslav Ganov * and delete the file yourself.
46b450d0d4d7fca16674fea02f15e21dc737352c40Svetoslav *
47b450d0d4d7fca16674fea02f15e21dc737352c40Svetoslav * @hide
484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */
499abf735387329758ca310acad3baa70eee1dba42Svetoslavpublic class PrintFileDocumentAdapter extends PrintDocumentAdapter {
504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
511c8f1e06a609507533609b4e04161c1c4fcb2849Philip P. Moltmann    private static final String LOG_TAG = "PrintedFileDocAdapter";
524b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
5317b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav    private final Context mContext;
5417b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav
554b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private final File mFile;
564b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
57798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    private final PrintDocumentInfo mDocumentInfo;
58798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov
594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private WriteFileAsyncTask mWriteFileAsyncTask;
604b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
61798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    /**
62798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * Constructor.
63798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     *
64798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @param context Context for accessing resources.
6519fba5d34a444ce145ab0d3a12c578d9d5d3f38cSvetoslav Ganov     * @param file The PDF file to print.
66798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     * @param documentInfo The information about the printed file.
67798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov     */
68798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov    public PrintFileDocumentAdapter(Context context, File file,
69798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov            PrintDocumentInfo documentInfo) {
704b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        if (file == null) {
714b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            throw new IllegalArgumentException("File cannot be null!");
724b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
73798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov        if (documentInfo == null) {
74798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov            throw new IllegalArgumentException("documentInfo cannot be null!");
75798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov        }
7617b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        mContext = context;
774b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mFile = file;
78798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov        mDocumentInfo = documentInfo;
794b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
804b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
814b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
82a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
836283608e0bd40548742839f5a8b02f7e5c9c5c7cSvetoslav            CancellationSignal cancellationSignal, LayoutResultCallback callback,
846283608e0bd40548742839f5a8b02f7e5c9c5c7cSvetoslav            Bundle metadata) {
85798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov        callback.onLayoutFinished(mDocumentInfo, false);
86a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
87a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
88a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    @Override
89d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    public void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
90a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            CancellationSignal cancellationSignal, WriteResultCallback callback) {
9117b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        mWriteFileAsyncTask = new WriteFileAsyncTask(destination, cancellationSignal, callback);
924b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mWriteFileAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
934b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                (Void[]) null);
944b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
954b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
9617b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav    private final class WriteFileAsyncTask extends AsyncTask<Void, Void, Void> {
974b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
98d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        private final ParcelFileDescriptor mDestination;
994b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
100a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final WriteResultCallback mResultCallback;
1014b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1024b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        private final CancellationSignal mCancellationSignal;
1034b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
104d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        public WriteFileAsyncTask(ParcelFileDescriptor destination,
105a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                CancellationSignal cancellationSignal, WriteResultCallback callback) {
1064b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            mDestination = destination;
107fd90651cfcc7e2b75254666fd6861038b72fb4acSvetoslav            mResultCallback = callback;
10817b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav            mCancellationSignal = cancellationSignal;
1094b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            mCancellationSignal.setOnCancelListener(new OnCancelListener() {
1104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                @Override
1114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                public void onCancel() {
1124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    cancel(true);
1134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                }
1144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            });
1154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
1164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
1184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        protected Void doInBackground(Void... params) {
11945c97df89d6c9d8b5252ba9fc27c41e75c81254dJeff Sharkey            try (InputStream in = new FileInputStream(mFile);
12045c97df89d6c9d8b5252ba9fc27c41e75c81254dJeff Sharkey                    OutputStream out = new FileOutputStream(mDestination.getFileDescriptor())) {
12145c97df89d6c9d8b5252ba9fc27c41e75c81254dJeff Sharkey                FileUtils.copy(in, out, null, mCancellationSignal);
12245c97df89d6c9d8b5252ba9fc27c41e75c81254dJeff Sharkey            } catch (OperationCanceledException e) {
12345c97df89d6c9d8b5252ba9fc27c41e75c81254dJeff Sharkey                // Ignored; already handled below
12445c97df89d6c9d8b5252ba9fc27c41e75c81254dJeff Sharkey            } catch (IOException e) {
12545c97df89d6c9d8b5252ba9fc27c41e75c81254dJeff Sharkey                Log.e(LOG_TAG, "Error writing data!", e);
12645c97df89d6c9d8b5252ba9fc27c41e75c81254dJeff Sharkey                mResultCallback.onWriteFailed(mContext.getString(
12745c97df89d6c9d8b5252ba9fc27c41e75c81254dJeff Sharkey                        R.string.write_fail_reason_cannot_write));
1284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
1294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            return null;
1304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
13117b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav
13217b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        @Override
13317b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        protected void onPostExecute(Void result) {
13485b1f883056a1d74473fd9ce774948878f389ab6Svetoslav Ganov            mResultCallback.onWriteFinished(new PageRange[] {PageRange.ALL_PAGES});
13517b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        }
13617b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav
13717b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        @Override
13817b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        protected void onCancelled(Void result) {
13917b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav            mResultCallback.onWriteFailed(mContext.getString(
14017b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav                    R.string.write_fail_reason_cancelled));
14117b7f6e6d4ec9f5e9597bfd283f1c017b6c66275Svetoslav        }
1424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1434b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov}
1444b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
145