Home | History | Annotate | Download | only in com.example.android.pdfrendererbasic
      1 /*
      2  * Copyright (C) 2014 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 com.example.android.pdfrendererbasic;
     18 
     19 import android.app.Activity;
     20 import android.app.Fragment;
     21 import android.content.Context;
     22 import android.graphics.Bitmap;
     23 import android.graphics.pdf.PdfRenderer;
     24 import android.os.Bundle;
     25 import android.os.ParcelFileDescriptor;
     26 import android.view.LayoutInflater;
     27 import android.view.View;
     28 import android.view.ViewGroup;
     29 import android.widget.Button;
     30 import android.widget.ImageView;
     31 import android.widget.Toast;
     32 
     33 import java.io.File;
     34 import java.io.FileOutputStream;
     35 import java.io.IOException;
     36 import java.io.InputStream;
     37 
     38 /**
     39  * This fragment has a big {@ImageView} that shows PDF pages, and 2 {@link android.widget.Button}s to move between
     40  * pages. We use a {@link android.graphics.pdf.PdfRenderer} to render PDF pages as {@link android.graphics.Bitmap}s.
     41  */
     42 public class PdfRendererBasicFragment extends Fragment implements View.OnClickListener {
     43 
     44     /**
     45      * Key string for saving the state of current page index.
     46      */
     47     private static final String STATE_CURRENT_PAGE_INDEX = "current_page_index";
     48 
     49     /**
     50      * The filename of the PDF.
     51      */
     52     private static final String FILENAME = "sample.pdf";
     53 
     54     /**
     55      * File descriptor of the PDF.
     56      */
     57     private ParcelFileDescriptor mFileDescriptor;
     58 
     59     /**
     60      * {@link android.graphics.pdf.PdfRenderer} to render the PDF.
     61      */
     62     private PdfRenderer mPdfRenderer;
     63 
     64     /**
     65      * Page that is currently shown on the screen.
     66      */
     67     private PdfRenderer.Page mCurrentPage;
     68 
     69     /**
     70      * {@link android.widget.ImageView} that shows a PDF page as a {@link android.graphics.Bitmap}
     71      */
     72     private ImageView mImageView;
     73 
     74     /**
     75      * {@link android.widget.Button} to move to the previous page.
     76      */
     77     private Button mButtonPrevious;
     78 
     79     /**
     80      * {@link android.widget.Button} to move to the next page.
     81      */
     82     private Button mButtonNext;
     83 
     84     public PdfRendererBasicFragment() {
     85     }
     86 
     87     @Override
     88     public View onCreateView(LayoutInflater inflater, ViewGroup container,
     89                              Bundle savedInstanceState) {
     90         return inflater.inflate(R.layout.fragment_pdf_renderer_basic, container, false);
     91     }
     92 
     93     @Override
     94     public void onViewCreated(View view, Bundle savedInstanceState) {
     95         super.onViewCreated(view, savedInstanceState);
     96         // Retain view references.
     97         mImageView = (ImageView) view.findViewById(R.id.image);
     98         mButtonPrevious = (Button) view.findViewById(R.id.previous);
     99         mButtonNext = (Button) view.findViewById(R.id.next);
    100         // Bind events.
    101         mButtonPrevious.setOnClickListener(this);
    102         mButtonNext.setOnClickListener(this);
    103         // Show the first page by default.
    104         int index = 0;
    105         // If there is a savedInstanceState (screen orientations, etc.), we restore the page index.
    106         if (null != savedInstanceState) {
    107             index = savedInstanceState.getInt(STATE_CURRENT_PAGE_INDEX, 0);
    108         }
    109         showPage(index);
    110     }
    111 
    112     @Override
    113     public void onAttach(Activity activity) {
    114         super.onAttach(activity);
    115         try {
    116             openRenderer(activity);
    117         } catch (IOException e) {
    118             e.printStackTrace();
    119             Toast.makeText(activity, "Error! " + e.getMessage(), Toast.LENGTH_SHORT).show();
    120             activity.finish();
    121         }
    122     }
    123 
    124     @Override
    125     public void onDetach() {
    126         try {
    127             closeRenderer();
    128         } catch (IOException e) {
    129             e.printStackTrace();
    130         }
    131         super.onDetach();
    132     }
    133 
    134     @Override
    135     public void onSaveInstanceState(Bundle outState) {
    136         super.onSaveInstanceState(outState);
    137         if (null != mCurrentPage) {
    138             outState.putInt(STATE_CURRENT_PAGE_INDEX, mCurrentPage.getIndex());
    139         }
    140     }
    141 
    142     /**
    143      * Sets up a {@link android.graphics.pdf.PdfRenderer} and related resources.
    144      */
    145     private void openRenderer(Context context) throws IOException {
    146         // In this sample, we read a PDF from the assets directory.
    147         File file = new File(context.getCacheDir(), FILENAME);
    148         if (!file.exists()) {
    149             // Since PdfRenderer cannot handle the compressed asset file directly, we copy it into
    150             // the cache directory.
    151             InputStream asset = context.getAssets().open(FILENAME);
    152             FileOutputStream output = new FileOutputStream(file);
    153             final byte[] buffer = new byte[1024];
    154             int size;
    155             while ((size = asset.read(buffer)) != -1) {
    156                 output.write(buffer, 0, size);
    157             }
    158             asset.close();
    159             output.close();
    160         }
    161         mFileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
    162         // This is the PdfRenderer we use to render the PDF.
    163         mPdfRenderer = new PdfRenderer(mFileDescriptor);
    164     }
    165 
    166     /**
    167      * Closes the {@link android.graphics.pdf.PdfRenderer} and related resources.
    168      *
    169      * @throws java.io.IOException When the PDF file cannot be closed.
    170      */
    171     private void closeRenderer() throws IOException {
    172         if (null != mCurrentPage) {
    173             mCurrentPage.close();
    174         }
    175         mPdfRenderer.close();
    176         mFileDescriptor.close();
    177     }
    178 
    179     /**
    180      * Shows the specified page of PDF to the screen.
    181      *
    182      * @param index The page index.
    183      */
    184     private void showPage(int index) {
    185         if (mPdfRenderer.getPageCount() <= index) {
    186             return;
    187         }
    188         // Make sure to close the current page before opening another one.
    189         if (null != mCurrentPage) {
    190             mCurrentPage.close();
    191         }
    192         // Use `openPage` to open a specific page in PDF.
    193         mCurrentPage = mPdfRenderer.openPage(index);
    194         // Important: the destination bitmap must be ARGB (not RGB).
    195         Bitmap bitmap = Bitmap.createBitmap(mCurrentPage.getWidth(), mCurrentPage.getHeight(),
    196                 Bitmap.Config.ARGB_8888);
    197         // Here, we render the page onto the Bitmap.
    198         // To render a portion of the page, use the second and third parameter. Pass nulls to get
    199         // the default result.
    200         // Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter.
    201         mCurrentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
    202         // We are ready to show the Bitmap to user.
    203         mImageView.setImageBitmap(bitmap);
    204         updateUi();
    205     }
    206 
    207     /**
    208      * Updates the state of 2 control buttons in response to the current page index.
    209      */
    210     private void updateUi() {
    211         int index = mCurrentPage.getIndex();
    212         int pageCount = mPdfRenderer.getPageCount();
    213         mButtonPrevious.setEnabled(0 != index);
    214         mButtonNext.setEnabled(index + 1 < pageCount);
    215         getActivity().setTitle(getString(R.string.app_name_with_index, index + 1, pageCount));
    216     }
    217 
    218     /**
    219      * Gets the number of pages in the PDF. This method is marked as public for testing.
    220      *
    221      * @return The number of pages.
    222      */
    223     public int getPageCount() {
    224         return mPdfRenderer.getPageCount();
    225     }
    226 
    227     @Override
    228     public void onClick(View view) {
    229         switch (view.getId()) {
    230             case R.id.previous: {
    231                 // Move to the previous page
    232                 showPage(mCurrentPage.getIndex() - 1);
    233                 break;
    234             }
    235             case R.id.next: {
    236                 // Move to the next page
    237                 showPage(mCurrentPage.getIndex() + 1);
    238                 break;
    239             }
    240         }
    241     }
    242 
    243 }
    244