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