Android-Pdf-Viewer-Library/PdfView/src/main/java/net/sf/andpdf/pdfviewer/PdfViewerFragment.java

426 lines
14 KiB
Java

package net.sf.andpdf.pdfviewer;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.sun.pdfview.PDFFile;
import com.sun.pdfview.PDFImage;
import com.sun.pdfview.PDFPage;
import com.sun.pdfview.PDFPaint;
import com.sun.pdfview.decrypt.PDFAuthenticationFailureException;
import com.sun.pdfview.decrypt.PDFPassword;
import com.sun.pdfview.font.PDFFont;
import net.sf.andpdf.nio.ByteBuffer;
import net.sf.andpdf.refs.HardReference;
import java.io.IOException;
import uk.co.senab.photoview.PhotoViewAttacher;
import static android.content.Context.INPUT_METHOD_SERVICE;
/**
* U:\Android\android-sdk-windows-1.5_r1\tools\adb push u:\Android\simple_T.pdf /data/test.pdf
*
* @author ferenc.hechler
*/
public class PdfViewerFragment extends Fragment {
private static final int STARTPAGE = 1;
private static final String TAG = "PDFVIEWER";
public static final boolean DEFAULTSHOWIMAGES = true;
public static final boolean DEFAULTANTIALIAS = true;
public static final boolean DEFAULTUSEFONTSUBSTITUTION = false;
private GraphView mGraphView;
private PDFFile mPdfFile;
public static byte[] byteArray;
private int mPage;
private ProgressDialog progress;
private TextView pageNumbersView;
private PDFPage mPdfPage;
private Thread backgroundThread;
private Handler uiHandler;
private boolean passwordNeeded;
private String password;
@Nullable
@Override
public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) {
uiHandler = new Handler();
progress = ProgressDialog.show(getActivity(), "Loading", "Loading PDF Page", true, true);
mGraphView = new GraphView(getActivity());
PDFImage.sShowImages = PdfViewerFragment.DEFAULTSHOWIMAGES;
PDFPaint.s_doAntiAlias = PdfViewerFragment.DEFAULTANTIALIAS;
PDFFont.sUseFontSubstitution = PdfViewerFragment.DEFAULTUSEFONTSUBSTITUTION;
HardReference.sKeepCaches = true;
mPage = STARTPAGE;
final Toolbar toolbar = (Toolbar) LayoutInflater.from(getActivity()).inflate(R.layout.pfd_toolbar, null);
toolbar.setContentInsetsAbsolute(0, 0);
toolbar.findViewById(R.id.pdf_toolbar_close_image).setOnClickListener(new OnClickListener() {
@Override
public void onClick(final View v) {
getFragmentManager().popBackStack();
}
});
replaceView(((ActionBarHidden) getActivity()).getCurrentActivityToolbarReplacedBy(toolbar), toolbar);
pageNumbersView = (TextView) toolbar.findViewById(R.id.pdf_toolbar_page_numbers_text_view);
return setContent(password);
}
@Override
public void onViewCreated(final View view, @Nullable final Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (view == null) {
getFragmentManager().popBackStack();
return;
}
if (!passwordNeeded) {
startRenderThread(mPage);
} else {
hideProgressBar();
final EditText etPW = (EditText) view.findViewById(getPdfPasswordEditField());
Button btOK = (Button) view.findViewById(getPdfPasswordOkButton());
Button btExit = (Button) view.findViewById(getPdfPasswordExitButton());
btOK.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
password = etPW.getText().toString();
getFragmentManager()
.beginTransaction()
.detach(PdfViewerFragment.this)
.attach(PdfViewerFragment.this)
.commit();
hideSoftInput();
}
});
btExit.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
hideSoftInput();
getFragmentManager().popBackStack();
}
});
}
}
@Nullable
private View setContent(@Nullable final String password) {
try {
openFile(byteArray, password);
passwordNeeded = false;
return mGraphView;
} catch (PDFAuthenticationFailureException e) {
passwordNeeded = true;
return LayoutInflater.from(getActivity()).inflate(R.layout.pdf_file_password, null);
} catch (Exception ex) {
Log.e(TAG, "an unexpected exception occurred");
}
return null;
}
private synchronized void startRenderThread(final int page) {
if (backgroundThread != null) return;
backgroundThread = new Thread(new Runnable() {
public void run() {
try {
if (mPdfFile != null) {
showPage(page);
}
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
backgroundThread = null;
}
});
updateImageStatus();
backgroundThread.start();
}
private void updateImageStatus() {
if (backgroundThread == null) {
return;
}
mGraphView.postDelayed(new Runnable() {
public void run() {
updateImageStatus();
}
}, 1000);
}
private void nextPage() {
if (mPdfFile != null) {
if (mPage < mPdfFile.getNumPages()) {
mPage += 1;
updatePageNumbersView();
progress = ProgressDialog.show(getActivity(), "Loading", "Loading PDF Page " + mPage, true, true);
startRenderThread(mPage);
}
}
}
private void prevPage() {
if (mPdfFile != null) {
if (mPage > 1) {
mPage -= 1;
updatePageNumbersView();
progress = ProgressDialog.show(getActivity(), "Loading", "Loading PDF Page " + mPage, true, true);
startRenderThread(mPage);
}
}
}
private void updatePageNumbersView() {
if (mPdfPage != null) {
if (mPdfPage.getPageNumber() == mPdfFile.getNumPages() && mPdfPage.getPageNumber() == 1) {
pageNumbersView.setVisibility(View.GONE);
} else {
pageNumbersView.setText(mPdfPage.getPageNumber() + "/" + mPdfFile.getNumPages());
}
}
}
/**
* Hides device keyboard that is showing over {@link Activity}.
* Do NOT use it if keyboard is over {@link android.app.Dialog} - it won't work as they have different {@link Activity#getWindow()}.
*/
public void hideSoftInput() {
if (getActivity().getCurrentFocus() == null) {
return;
}
final InputMethodManager inputManager = (InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), 0);
getActivity().getWindow().getDecorView().requestFocus();
}
private class GraphView extends FrameLayout {
public Bitmap mBi;
public ImageView pdfZoomedImageView;
public PhotoViewAttacher photoViewAttacher;
public GraphView(Context context) {
super(context);
final FrameLayout.LayoutParams frameLayout = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
frameLayout.gravity = Gravity.CENTER;
pdfZoomedImageView = new ImageView(context);
pdfZoomedImageView.setLayoutParams(frameLayout);
pdfZoomedImageView.setBackgroundColor(getContext().getResources().getColor(R.color.zoomed_image_view_background));
photoViewAttacher = new PhotoViewAttacher(pdfZoomedImageView);
photoViewAttacher.setOnSingleFlingListener(new OnSwipeTouchListener() {
@Override
public void onSwipeLeft() {
nextPage();
}
@Override
public void onSwipeRight() {
prevPage();
}
});
setPageBitmap(null);
//updateImage();
final LinearLayout.LayoutParams linearLayout = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
setLayoutParams(linearLayout);
addView(pdfZoomedImageView);
}
private void updateImage() {
uiHandler.post(new Runnable() {
public void run() {
pdfZoomedImageView.setImageBitmap(mBi);
photoViewAttacher.update();
updatePageNumbersView();
}
});
}
private void setPageBitmap(Bitmap bi) {
if (bi != null) {
mBi = bi;
}
}
}
// TODO: refactor
private void showPage(final int page) {
// on some Android getWidth() and getHeight() returns 0, so we need to wait until UI is ready
try {
// free memory from previous page
mGraphView.setPageBitmap(null);
mGraphView.updateImage();
// Only load the page if it's a different page (i.e. not just changing the zoom level)
if (mPdfPage == null || mPdfPage.getPageNumber() != page) {
mPdfPage = mPdfFile.getPage(page, true);
}
final int scale = 3;
double width = mPdfPage.getWidth() * scale;
double height = mPdfPage.getHeight() * scale;
int maxWidthToPopulate = mGraphView.getWidth();
int maxHeightToPopulate = mGraphView.getHeight();
int calculatedWidth;
int calculatedHeight;
final double widthRatio = width / maxWidthToPopulate;
final double heightRatio = height / maxHeightToPopulate;
if (width < maxWidthToPopulate && height < maxHeightToPopulate) {
if (widthRatio > heightRatio) {
calculatedWidth = (int) (width / widthRatio);
calculatedHeight = (int) (height / widthRatio);
} else {
calculatedWidth = (int) (width / heightRatio);
calculatedHeight = (int) (height / heightRatio);
}
} else {
if (widthRatio > 1 && heightRatio > 1) {
if (widthRatio > heightRatio) {
calculatedHeight = (int) (height / widthRatio);
calculatedWidth = (int) (width / widthRatio);
} else {
calculatedHeight = (int) (height / heightRatio);
calculatedWidth = (int) (width / heightRatio);
}
} else {
if (widthRatio > heightRatio) {
calculatedHeight = (int) (height / widthRatio);
calculatedWidth = (int) (width / widthRatio);
} else {
calculatedHeight = (int) (height / heightRatio);
calculatedWidth = (int) (width / heightRatio);
}
}
}
final Bitmap bitmap = mPdfPage.getImage(calculatedWidth, calculatedHeight, null, true, true);
mGraphView.setPageBitmap(bitmap);
mGraphView.updateImage();
} catch (Throwable e) {
Log.e(TAG, e.getMessage(), e);
}
hideProgressBar();
}
private void hideProgressBar() {
if (progress != null) {
progress.dismiss();
}
}
/**
* <p>Open a specific pdf file. Creates a DocumentInfo from the file,
* and opens that.</p>
* <p/>
* <p><b>Note:</b> Mapping the file locks the file until the PDFFile
* is closed.</p>
*
* @param byteArray the file to open
* @throws IOException
*/
public void openFile(final byte[] byteArray, String password) throws IOException {
if (byteArray != null) {
// now memory-map a byte-buffer
ByteBuffer bb = ByteBuffer.NEW(byteArray);
// create a PDFFile from the data
if (password == null) {
mPdfFile = new PDFFile(bb);
} else {
mPdfFile = new PDFFile(bb, new PDFPassword(password));
}
} else {
hideProgressBar();
getFragmentManager().popBackStack();
}
}
@Override
public void onDestroy() {
super.onDestroy();
byteArray = null;
if (mGraphView != null) {
mGraphView.mBi = null;
mGraphView.photoViewAttacher.cleanup();
}
}
public static ViewGroup getParent(View view) {
return (ViewGroup) view.getParent();
}
public static void removeView(View view) {
ViewGroup parent = getParent(view);
if (parent != null) {
parent.removeView(view);
}
}
public static void replaceView(View currentView, View newView) {
ViewGroup parent = getParent(currentView);
if (parent == null) {
return;
}
final int index = parent.indexOfChild(currentView);
removeView(currentView);
parent.addView(newView, index);
}
private int getPdfPasswordEditField() {
return R.id.etPassword;
}
private int getPdfPasswordOkButton() {
return R.id.btOK;
}
private int getPdfPasswordExitButton() {
return R.id.btExit;
}
public interface ActionBarHidden {
Toolbar getCurrentActivityToolbarReplacedBy(@NonNull final Toolbar toolbar);
}
}