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