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