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
17package com.example.android.pdfrendererbasic;
18
19import android.app.Activity;
20import android.app.Fragment;
21import android.content.Context;
22import android.graphics.Bitmap;
23import android.graphics.pdf.PdfRenderer;
24import android.os.Bundle;
25import android.os.ParcelFileDescriptor;
26import android.view.LayoutInflater;
27import android.view.View;
28import android.view.ViewGroup;
29import android.widget.Button;
30import android.widget.ImageView;
31import android.widget.Toast;
32
33import 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 */
39public 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
76    public PdfRendererBasicFragment() {
77    }
78
79    @Override
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
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
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
117    public void onDetach() {
118        try {
119            closeRenderer();
120        } catch (IOException e) {
121            e.printStackTrace();
122        }
123        super.onDetach();
124    }
125
126    @Override
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     */
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     */
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     */
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     */
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     */
201    public int getPageCount() {
202        return mPdfRenderer.getPageCount();
203    }
204
205    @Override
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