Home | History | Annotate | Download | only in print
      1 /*
      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 
     17 package foo.bar.print;
     18 
     19 import java.io.FileOutputStream;
     20 import java.io.IOException;
     21 import java.util.ArrayList;
     22 import java.util.List;
     23 
     24 import android.app.Activity;
     25 import android.content.Context;
     26 import android.graphics.pdf.PdfDocument.Page;
     27 import android.os.AsyncTask;
     28 import android.os.Bundle;
     29 import android.os.CancellationSignal;
     30 import android.os.CancellationSignal.OnCancelListener;
     31 import android.os.ParcelFileDescriptor;
     32 import android.print.PageRange;
     33 import android.print.PrintAttributes;
     34 import android.print.PrintDocumentAdapter;
     35 import android.print.PrintDocumentInfo;
     36 import android.print.PrintManager;
     37 import android.print.pdf.PrintedPdfDocument;
     38 import android.util.SparseIntArray;
     39 import android.view.Menu;
     40 import android.view.MenuItem;
     41 import android.view.View;
     42 
     43 /**
     44  * Simple sample of how to use the print APIs.
     45  */
     46 public class PrintActivity extends Activity {
     47 
     48     public static final String LOG_TAG = "PrintActivity";
     49 
     50     private static final int PAGE_COUNT = 5;
     51 
     52     @Override
     53     protected void onCreate(Bundle savedInstanceState) {
     54         super.onCreate(savedInstanceState);
     55         setContentView(R.layout.activity_main);
     56     }
     57 
     58     @Override
     59     public boolean onCreateOptionsMenu(Menu menu) {
     60         super.onCreateOptionsMenu(menu);
     61         getMenuInflater().inflate(R.menu.activity_main, menu);
     62         return true;
     63     }
     64 
     65     @Override
     66     public boolean onOptionsItemSelected(MenuItem item) {
     67         if (item.getItemId() == R.id.menu_print) {
     68             printView();
     69             return true;
     70         }
     71         return super.onOptionsItemSelected(item);
     72     }
     73 
     74     private void printView() {
     75         PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE);
     76         final View view = findViewById(R.id.content);
     77 
     78         printManager.print("Print_View",
     79             new PrintDocumentAdapter() {
     80                 private static final int RESULT_LAYOUT_FAILED = 1;
     81                 private static final int RESULT_LAYOUT_FINISHED = 2;
     82 
     83                 private PrintAttributes mPrintAttributes;
     84 
     85                 @Override
     86                 public void onLayout(final PrintAttributes oldAttributes,
     87                         final PrintAttributes newAttributes,
     88                         final CancellationSignal cancellationSignal,
     89                         final LayoutResultCallback callback,
     90                         final Bundle metadata) {
     91 
     92                     new AsyncTask<Void, Void, Integer>() {
     93                         @Override
     94                         protected void onPreExecute() {
     95                             // First register for cancellation requests.
     96                             cancellationSignal.setOnCancelListener(new OnCancelListener() {
     97                                 @Override
     98                                 public void onCancel() {
     99                                     cancel(true);
    100                                 }
    101                             });
    102                             mPrintAttributes = newAttributes;
    103                         }
    104 
    105                         @Override
    106                         protected Integer doInBackground(Void... params) {
    107                             try {
    108                                 // Pretend we do some layout work.
    109                                 for (int i = 0; i < PAGE_COUNT; i++) {
    110                                     // Be nice and respond to cancellation.
    111                                     if (isCancelled()) {
    112                                         return null;
    113                                     }
    114                                     pretendDoingLayoutWork();
    115                                 }
    116                                 return RESULT_LAYOUT_FINISHED;
    117                             } catch (Exception e) {
    118                                 return RESULT_LAYOUT_FAILED;
    119                             }
    120                         }
    121 
    122                         @Override
    123                         protected void onPostExecute(Integer result) {
    124                             // The task was not cancelled, so handle the layout result.
    125                             switch (result) {
    126                                 case RESULT_LAYOUT_FINISHED: {
    127                                     PrintDocumentInfo info = new PrintDocumentInfo
    128                                             .Builder("print_view.pdf")
    129                                             .setContentType(PrintDocumentInfo
    130                                                     .CONTENT_TYPE_DOCUMENT)
    131                                             .setPageCount(PAGE_COUNT)
    132                                             .build();
    133                                     callback.onLayoutFinished(info, false);
    134                                 } break;
    135 
    136                                 case RESULT_LAYOUT_FAILED: {
    137                                     callback.onLayoutFailed(null);
    138                                 } break;
    139                             }
    140                         }
    141 
    142                         @Override
    143                         protected void onCancelled(Integer result) {
    144                             // Task was cancelled, report that.
    145                             callback.onLayoutCancelled();
    146                         }
    147 
    148                         private void pretendDoingLayoutWork() throws Exception {
    149 
    150                         }
    151                     }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
    152                 }
    153 
    154                 @Override
    155                 public void onWrite(final PageRange[] pages,
    156                         final ParcelFileDescriptor destination,
    157                         final CancellationSignal canclleationSignal,
    158                         final WriteResultCallback callback) {
    159 
    160                     new AsyncTask<Void, Void, Integer>() {
    161                         private static final int RESULT_WRITE_FAILED = 1;
    162                         private static final int RESULT_WRITE_FINISHED = 2;
    163 
    164                         private final SparseIntArray mWrittenPages = new SparseIntArray();
    165                         private final PrintedPdfDocument mPdfDocument = new PrintedPdfDocument(
    166                                 PrintActivity.this, mPrintAttributes);
    167 
    168                         @Override
    169                         protected void onPreExecute() {
    170                             // First register for cancellation requests.
    171                             canclleationSignal.setOnCancelListener(new OnCancelListener() {
    172                                 @Override
    173                                 public void onCancel() {
    174                                     cancel(true);
    175                                 }
    176                             });
    177 
    178                             for (int i = 0; i < PAGE_COUNT; i++) {
    179                                 // Be nice and respond to cancellation.
    180                                 if (isCancelled()) {
    181                                     return;
    182                                 }
    183 
    184                                 // Write the page only if it was requested.
    185                                 if (containsPage(pages, i)) {
    186                                     mWrittenPages.append(mWrittenPages.size(), i);
    187                                     Page page = mPdfDocument.startPage(i);
    188                                     // The page of the PDF backed canvas size is in pixels (1/72") and
    189                                     // smaller that the view. We scale down the drawn content and to
    190                                     // fit. This does not lead to losing data as PDF is a vector format.
    191                                     final float scale = (float) Math.min(mPdfDocument.getPageWidth(),
    192                                             mPdfDocument.getPageHeight()) / Math.max(view.getWidth(), view.getHeight());
    193                                     page.getCanvas().scale(scale, scale);
    194                                     view.draw(page.getCanvas());
    195                                     mPdfDocument.finishPage(page);
    196                                 }
    197                             }
    198                         }
    199 
    200                         @Override
    201                         protected Integer doInBackground(Void... params) {
    202                             // Write the data and return success or failure.
    203                             try {
    204                                 mPdfDocument.writeTo(new FileOutputStream(
    205                                         destination.getFileDescriptor()));
    206                                 return RESULT_WRITE_FINISHED;
    207                             } catch (IOException ioe) {
    208                                 return RESULT_WRITE_FAILED;
    209                             }
    210                         }
    211 
    212                         @Override
    213                         protected void onPostExecute(Integer result) {
    214                             // The task was not cancelled, so handle the write result.
    215                             switch (result) {
    216                                 case RESULT_WRITE_FINISHED: {
    217                                     PageRange[] pageRanges = computePageRanges(mWrittenPages);
    218                                     callback.onWriteFinished(pageRanges);
    219                                 } break;
    220 
    221                                 case RESULT_WRITE_FAILED: {
    222                                     callback.onWriteFailed(null);
    223                                 } break;
    224                             }
    225 
    226                             mPdfDocument.close();
    227                         }
    228 
    229                         @Override
    230                         protected void onCancelled(Integer result) {
    231                             // Task was cancelled, report that.
    232                             callback.onWriteCancelled();
    233                             mPdfDocument.close();
    234                         }
    235                     }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
    236                 }
    237 
    238                 private PageRange[] computePageRanges(SparseIntArray writtenPages) {
    239                     List<PageRange> pageRanges = new ArrayList<PageRange>();
    240 
    241                     int start = -1;
    242                     int end = -1;
    243                     final int writtenPageCount = writtenPages.size();
    244                     for (int i = 0; i < writtenPageCount; i++) {
    245                         if (start < 0) {
    246                             start = writtenPages.valueAt(i);
    247                         }
    248                         int oldEnd = end = start;
    249                         while (i < writtenPageCount && (end - oldEnd) <= 1) {
    250                             oldEnd = end;
    251                             end = writtenPages.valueAt(i);
    252                             i++;
    253                         }
    254                         PageRange pageRange = new PageRange(start, end);
    255                         pageRanges.add(pageRange);
    256                         start = end = -1;
    257                     }
    258 
    259                     PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
    260                     pageRanges.toArray(pageRangesArray);
    261                     return pageRangesArray;
    262                 }
    263 
    264                 private boolean containsPage(PageRange[] pageRanges, int page) {
    265                     final int pageRangeCount = pageRanges.length;
    266                     for (int i = 0; i < pageRangeCount; i++) {
    267                         if (pageRanges[i].getStart() <= page
    268                                 && pageRanges[i].getEnd() >= page) {
    269                             return true;
    270                         }
    271                     }
    272                     return false;
    273                 }
    274         }, null);
    275     }
    276 }
    277