1

I am working on an android app that requires browsing a pdf from phone and then storing it's content into a String. I have the following code:

 //src= location of the pdf file obtained from while browsing pdf from the phone (eg:"/sdcard/bluetooth/My_pdf.pdf")
        public void convertPDFToText(String src) {
        try {
               //create pdf reader
               PdfReader pr = new PdfReader(src);    

              //get the number of pages in the document
               int pNum = pr.getNumberOfPages();

            //extract text from each page and write it to the output text file
            for (int page = 1; page <= pNum; page++) {

            //text is the required String (initialized as "" )
            text = text + PdfTextExtractor.getTextFromPage(pr, page);
              }
            } catch (Exception e) {
        e.printStackTrace();
           }
         }

When I run this code separately in a java file, it runs perfectly fine (changing the src input according to the location of the pdf in the system), but when I run the same code in android studio, it gives me an exception saying:

java.io.IOException: /sdcard/bluetooth/My_pdf.pdf not found as file or resource.
at com.itextpdf.text.io.RandomAccessSourceFactory.createByReadingToMemory(RandomAccessSourceFactory.java:263)
at com.itextpdf.text.io.RandomAccessSourceFactory.createBestSource(RandomAccessSourceFactory.java:173)
at com.itextpdf.text.pdf.PdfReader.<init>(PdfReader.java:223)
at com.itextpdf.text.pdf.PdfReader.<init>(PdfReader.java:207)
at com.itextpdf.text.pdf.PdfReader.<init>(PdfReader.java:197)
at com.example.prachisingh.summer.DisplayActivity.convertPDFToText(DisplayActivity.java:112)
at com.example.prachisingh.summer.DisplayActivity.onCreate(DisplayActivity.java:70)
at android.app.Activity.performCreate(Activity.java:6259)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1130)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2379)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1354)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5443)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) resource.I need help figuring out the cause of this error.

Here is my AndroidMAnifest.xml file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.Computer.app_name">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name=".DisplayActivity" >
    </activity>

    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />
</application>

scottstots
  • 155
  • 2
  • 17
  • Did you add the permissions to write to external storage? Please show us your `Manifest.xml` file. – ishmaelMakitla May 30 '16 at 17:53
  • Are you sure the file exists? Try calling `file.exists()` to make sure. – TychoTheTaco May 30 '16 at 18:18
  • @ishmaelMakitla I had already given permissions to read and write the external storage. I have also added my AndroidManifest.xml file. – scottstots May 31 '16 at 04:25
  • @TychoTheTaco I checked if the file exists on the location I am trying to input in my convertPDFToText function, and it gives me **true** .But I still get the same error. – scottstots May 31 '16 at 04:28
  • I am in desperate need of knowing your exact **src** path. Try observing the path again if it's correct and well formatted. – Aown Raza May 31 '16 at 11:07
  • The example I gave is my exact src path. I have a pdf named My_pdf in bluetooth folder in sd card. Also I added a code to open My_pdf using the very same src path, and it works fine. _File file = new File(src) ; if (file.exists()) { Uri path = Uri.fromFile(file) ; Intent i = new Intent(Intent.ACTION_VIEW) ; i.setDataAndType(path, "application/pdf") ; startActivity(i);_ – scottstots May 31 '16 at 12:06
  • Use `Environment.getExternalStorageDirectory()` to get the path directory in a more "formal and right" way instead of hardcoding the path. – Aown Raza May 31 '16 at 12:34
  • @AownRaza I am not hardcoding the path. I am browsing pdf from phone and then getting it's path, using the code given on this [link](http://stackoverflow.com/questions/37302143/browse-and-upload-pdf-or-word-file-in-android/37309153#37309153?newreg=96d2efbe54044a1b840785c91f4df238). And the path is perfectly correct as I am able to view my pdf from the path obtained in Reader as well. Just that when I call convertPDFToText function on the same path, it gives me the above mentioned error. – scottstots Jun 01 '16 at 18:02
  • The [Link](http://stackoverflow.com/questions/37302143/browse-and-upload-pdf-or-word-file-in-android/37309153#37309153?newreg=96d2efbe54044a1b840785c91f4df238) you provided has no accepted answer. Try using [PDFBox](https://pdfbox.apache.org/) library. [This](http://stackoverflow.com/questions/10299839/how-to-read-pdf-in-my-android-application) SO post may also be helpful for you. – Aown Raza Jun 02 '16 at 04:51
  • I modified the code from the link I provided above. The link you provided gives solution to _displaying_ a pdf, while I want to read the text from the pdf and store it in a string. – scottstots Jun 02 '16 at 05:24

1 Answers1

0

Add permission:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

to your AndroidManifest.xml.

Also if your target SDK is 23 or higher you must request for this permission while the app is running. More info here

Example implementation may look like this:

  1. Create helper class for requesting permissions

    public class PermissionChecker {
    
        private final Activity activity;
        private final View layout;
        private final int requestCode;
        private final String permission;
        private final String description;
    
        public PermissionChecker(@NonNull Activity activity, @NonNull View layout,
                         int requestCode,
                         @NonNull String permission,
                         @NonNull String description) {
            this.activity = activity;
            this.layout = layout;
    
            this.requestCode = requestCode;
            this.permission = permission;
            this.description = description;
        }
    
        public void requestPermission() {
            if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
                // Provide an additional rationale to the user if the permission was not granted
                // and the user would benefit from additional context for the use of the permission.
                // Display a SnackBar with a button to request the missing permission.
                Snackbar.make(layout, description, Snackbar.LENGTH_INDEFINITE).setAction("OK", new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        requestPermission(activity, permission, requestCode);
                    }
                }).show();
            } else {
                // No explanation needed, we can request the permission.
                requestPermission(activity, permission, requestCode);
            }
        }
    
        public boolean checkPermission() {
            return ContextCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED;
        }
    
        public boolean onRequestPermissionsResult(int requestCode, int[] grantResults) {
            return requestCode == this.requestCode
                && ((grantResults.length > 0)
                && (grantResults[0] == PackageManager.PERMISSION_GRANTED));
        }
    
        private void requestPermission(Activity activityContext, String permission, int requestCode) {
            ActivityCompat.requestPermissions(activityContext, new String[] { permission }, requestCode);
        }
    }
    
  2. Your Activity should implement OnRequestPermissionsResultCallback

    implements ActivityCompat.OnRequestPermissionsResultCallback
  3. Init PermissionChecker for external storage permission.

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        // ...
    
        View rootView = getWindow().getDecorView().getRootView();
    
        readExternalStoragePermissionChecker = new PermissionChecker(this, rootView,
            PERMISSION_REQUEST_READ_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            "Read external storage access is required to read pdfs from sdcard."
            );
    
        if (readExternalStoragePermissionChecker.checkPermission()) {
            convertPDFToText(path);
        }
        else {
            readExternalStoragePermissionChecker.requestPermission();
        }
    
        // ...
    }
    
  4. Override onRequestPermissionsResult method in your Activity.

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (readExternalStoragePermissionChecker.onRequestPermissionsResult(requestCode, grantResults)) {
            convertPDFToText(path);
        }
    }
    
PiKos
  • 1,344
  • 1
  • 16
  • 15
  • @coder_91 Can you make one more test: **File file = new File(src); if (!file.canRead()){ throw new Exception("Read permission error"); }** – PiKos Jun 01 '16 at 18:35
  • On trying that, it gives me the exception saying "Read permission error". So, the file cannot be read. How can I sort that? – scottstots Jun 01 '16 at 18:53
  • What version of Android and what model of phone do you have? – PiKos Jun 01 '16 at 20:13
  • I am using MotoG(3rd generation) of Android version 6.0.1. – scottstots Jun 02 '16 at 04:15
  • Ok, I've updated my answer for Android 6 and sdk 23. It should work – PiKos Jun 02 '16 at 10:52
  • Thank you, but when I call the constructor of PermissionChecker as `readExternalStoragePermissionChecker = new PermissionChecker(this, rootView,PERMISSION_REQUEST_READ_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE,"Read external storage access is required to read pdfs from sdcard.")` I get this error saying: PermissionChecker() has private access in android.support.v4.content.PermissionChecker. Also I cannot access it's functions. How do I solve the problem? – scottstots Jun 03 '16 at 11:45
  • @coder_91 You're importing wrong **PermissionChecker** class (**android.support.v4.content.PermissionChecker**) - You should import PermissionChecker included in the answer code. – PiKos Jun 03 '16 at 11:53