Java程序  |  305行  |  13.08 KB

/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package foo.bar.print;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.graphics.pdf.PdfDocument.Page;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.CancellationSignal.OnCancelListener;
import android.os.ParcelFileDescriptor;
import android.print.PageRange;
import android.print.PrintAttributes;
import android.print.PrintDocumentAdapter;
import android.print.PrintDocumentInfo;
import android.print.PrintManager;
import android.print.pdf.PrintedPdfDocument;
import android.support.v4.print.PrintHelper;
import android.util.SparseIntArray;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

/**
 * Simple sample of how to use the print APIs.
 */
public class PrintActivity extends Activity {

    public static final String LOG_TAG = "PrintActivity";

    private static final int PAGE_COUNT = 5;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_print:
                printView();
                return true;
            case R.id.menu_print_uri_portrait_force:
            case R.id.menu_print_uri_portrait:
            case R.id.menu_print_uri_landscape:
                try {
                    PrintHelper ph = new PrintHelper(this);
                    Uri uri = null;
                    switch (item.getItemId()) {
                        case R.id.menu_print_uri_portrait_force:
                            ph.setOrientation(PrintHelper.ORIENTATION_PORTRAIT);
                            /* fall through */
                        case R.id.menu_print_uri_portrait:
                            uri = Uri.parse("android.resource://foo.bar.print/raw/portrait");
                            break;
                        case R.id.menu_print_uri_landscape:
                            uri = Uri.parse("android.resource://foo.bar.print/raw/landscape");
                            break;
                    }

                    ph.printBitmap("Print Uri", uri);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    private void printView() {
        PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE);
        final View view = findViewById(R.id.content);

        printManager.print("Print_View",
            new PrintDocumentAdapter() {
                private static final int RESULT_LAYOUT_FAILED = 1;
                private static final int RESULT_LAYOUT_FINISHED = 2;

                private PrintAttributes mPrintAttributes;

                @Override
                public void onLayout(final PrintAttributes oldAttributes,
                        final PrintAttributes newAttributes,
                        final CancellationSignal cancellationSignal,
                        final LayoutResultCallback callback,
                        final Bundle metadata) {

                    new AsyncTask<Void, Void, Integer>() {
                        @Override
                        protected void onPreExecute() {
                            // First register for cancellation requests.
                            cancellationSignal.setOnCancelListener(new OnCancelListener() {
                                @Override
                                public void onCancel() {
                                    cancel(true);
                                }
                            });
                            mPrintAttributes = newAttributes;
                        }

                        @Override
                        protected Integer doInBackground(Void... params) {
                            try {
                                // Pretend we do some layout work.
                                for (int i = 0; i < PAGE_COUNT; i++) {
                                    // Be nice and respond to cancellation.
                                    if (isCancelled()) {
                                        return null;
                                    }
                                    pretendDoingLayoutWork();
                                }
                                return RESULT_LAYOUT_FINISHED;
                            } catch (Exception e) {
                                return RESULT_LAYOUT_FAILED;
                            }
                        }

                        @Override
                        protected void onPostExecute(Integer result) {
                            // The task was not cancelled, so handle the layout result.
                            switch (result) {
                                case RESULT_LAYOUT_FINISHED: {
                                    PrintDocumentInfo info = new PrintDocumentInfo
                                            .Builder("print_view.pdf")
                                            .setContentType(PrintDocumentInfo
                                                    .CONTENT_TYPE_DOCUMENT)
                                            .setPageCount(PAGE_COUNT)
                                            .build();
                                    callback.onLayoutFinished(info, false);
                                } break;

                                case RESULT_LAYOUT_FAILED: {
                                    callback.onLayoutFailed(null);
                                } break;
                            }
                        }

                        @Override
                        protected void onCancelled(Integer result) {
                            // Task was cancelled, report that.
                            callback.onLayoutCancelled();
                        }

                        private void pretendDoingLayoutWork() throws Exception {

                        }
                    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
                }

                @Override
                public void onWrite(final PageRange[] pages,
                        final ParcelFileDescriptor destination,
                        final CancellationSignal canclleationSignal,
                        final WriteResultCallback callback) {

                    new AsyncTask<Void, Void, Integer>() {
                        private static final int RESULT_WRITE_FAILED = 1;
                        private static final int RESULT_WRITE_FINISHED = 2;

                        private final SparseIntArray mWrittenPages = new SparseIntArray();
                        private final PrintedPdfDocument mPdfDocument = new PrintedPdfDocument(
                                PrintActivity.this, mPrintAttributes);

                        @Override
                        protected void onPreExecute() {
                            // First register for cancellation requests.
                            canclleationSignal.setOnCancelListener(new OnCancelListener() {
                                @Override
                                public void onCancel() {
                                    cancel(true);
                                }
                            });

                            for (int i = 0; i < PAGE_COUNT; i++) {
                                // Be nice and respond to cancellation.
                                if (isCancelled()) {
                                    return;
                                }

                                // Write the page only if it was requested.
                                if (containsPage(pages, i)) {
                                    mWrittenPages.append(mWrittenPages.size(), i);
                                    Page page = mPdfDocument.startPage(i);
                                    // The page of the PDF backed canvas size is in pixels (1/72") and
                                    // smaller that the view. We scale down the drawn content and to
                                    // fit. This does not lead to losing data as PDF is a vector format.
                                    final float scale = (float) Math.min(mPdfDocument.getPageWidth(),
                                            mPdfDocument.getPageHeight()) / Math.max(view.getWidth(), view.getHeight());
                                    page.getCanvas().scale(scale, scale);
                                    view.draw(page.getCanvas());
                                    mPdfDocument.finishPage(page);
                                }
                            }
                        }

                        @Override
                        protected Integer doInBackground(Void... params) {
                            // Write the data and return success or failure.
                            try {
                                mPdfDocument.writeTo(new FileOutputStream(
                                        destination.getFileDescriptor()));
                                return RESULT_WRITE_FINISHED;
                            } catch (IOException ioe) {
                                return RESULT_WRITE_FAILED;
                            }
                        }

                        @Override
                        protected void onPostExecute(Integer result) {
                            // The task was not cancelled, so handle the write result.
                            switch (result) {
                                case RESULT_WRITE_FINISHED: {
                                    PageRange[] pageRanges = computePageRanges(mWrittenPages);
                                    callback.onWriteFinished(pageRanges);
                                } break;

                                case RESULT_WRITE_FAILED: {
                                    callback.onWriteFailed(null);
                                } break;
                            }

                            mPdfDocument.close();
                        }

                        @Override
                        protected void onCancelled(Integer result) {
                            // Task was cancelled, report that.
                            callback.onWriteCancelled();
                            mPdfDocument.close();
                        }
                    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
                }

                private PageRange[] computePageRanges(SparseIntArray writtenPages) {
                    List<PageRange> pageRanges = new ArrayList<PageRange>();
    
                    int start = -1;
                    int end = -1;
                    final int writtenPageCount = writtenPages.size(); 
                    for (int i = 0; i < writtenPageCount; i++) {
                        if (start < 0) {
                            start = writtenPages.valueAt(i);
                        }
                        int oldEnd = end = start;
                        while (i < writtenPageCount && (end - oldEnd) <= 1) {
                            oldEnd = end;
                            end = writtenPages.valueAt(i);
                            i++;
                        }
                        PageRange pageRange = new PageRange(start, end);
                        pageRanges.add(pageRange);
                        start = end = -1;
                    }
    
                    PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
                    pageRanges.toArray(pageRangesArray);
                    return pageRangesArray;
                }

                private boolean containsPage(PageRange[] pageRanges, int page) {
                    final int pageRangeCount = pageRanges.length;
                    for (int i = 0; i < pageRangeCount; i++) {
                        if (pageRanges[i].getStart() <= page
                                && pageRanges[i].getEnd() >= page) {
                            return true;
                        }
                    }
                    return false;
                }
        }, null);
    }
}