Search code examples
androidandroid-studiopdfitextpassword-protection

Set pdf file password in android studio


I am using this approach to generate pdf file with pdfDocument library. Here is my code wrapped in MainActivity.java file

declared variable

private static final int PERMISSION_REQUEST_CODE = 200;
Button generatePDFbtn;

// declaring width and height
// for our PDF file.
int pageHeight = 1120;
int pagewidth = 792;

// creating a bitmap variable
// for storing our images
Bitmap bmp, scaledbmp;

override oncreate function

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inScaled = false;

    generatePDFbtn = findViewById(R.id.idBtnGeneratePDF);
    bmp = BitmapFactory.decodeResource(this.getResources(), R.drawable.test.png, options);
    scaledbmp = Bitmap.createScaledBitmap(bmp, 140, 140, false);

    // below code is used for
    // checking our permissions.
    if (checkPermission()) {
        Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show();
    } else {
        requestPermission();
    }

    generatePDFbtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // calling method to
            // generate our PDF file.
            try {
                generatePDF();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    });
}

generatePDF function

private void generatePDF() throws FileNotFoundException {
      PdfDocument pdfDocument = new PdfDocument();
      Paint paint = new Paint();
      Paint title = new Paint();
      PdfDocument.PageInfo mypageInfo = new PdfDocument.PageInfo.Builder(pagewidth, pageHeight, 1).create();

      PdfDocument.Page myPage = pdfDocument.startPage(mypageInfo);

      Canvas canvas = myPage.getCanvas();

      canvas.drawBitmap(scaledbmp, 56, 40, paint);

      title.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
      title.setTextSize(15);
      title.setColor(ContextCompat.getColor(this, R.color.purple_200));

      canvas.drawText("A portal for IT professionals.", 209, 100, title);
      canvas.drawText("Geeks for Geeks", 209, 80, title);

      title.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
      title.setColor(ContextCompat.getColor(this, R.color.purple_200));
      title.setTextSize(15);

      title.setTextAlign(Paint.Align.CENTER);
      canvas.drawText("This is sample document which we have created.", 396, 560, title);

      pdfDocument.finishPage(myPage);

      File directoryFile = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);

      File saveFile = new File(directoryFile, "test.pdf");

      try {
          pdfDocument.writeTo(new FileOutputStream(saveFile));
          Toast.makeText(MainActivity.this, "PDF file generated successfully.", Toast.LENGTH_SHORT).show();
      } catch (IOException e) {
          e.printStackTrace();
      }
      pdfDocument.close();
  }

I googled anywhere to find how to set password for pdf file and it seems pdfDocument library does not provide a function to do so. Is there any library or way to set password when pdf file is created in android?

NOTE: I tried using itext core 7 with following version 7.2.0 but the pdf file which generated by code below is corrupted. I tried to downgrade the pdf library to worked version which 5.5.3.1, but that version is no longer exist anymore. Anyway, here is the way I am implementing generate pdf using itext core 7

String pdfPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString();
        File file = new File(pdfPath, "test.pdf");

        PdfWriter writer = new PdfWriter(file);
        PdfDocument pdfDocument = new PdfDocument(writer);
        Document document = new Document(pdfDocument);

        Paragraph paragraph = new Paragraph("Technology").setTextAlignment(TextAlignment.CENTER)
                .setFontSize(15);
        document.add(paragraph);
        document.close(); 

Solution

  • My problem solved using itext core 7.1^ as K J mentioned above. For those of you who want to know how the implementation or the code, here is how:

    build.gradle

    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        ... 
        implementation 'com.itextpdf:itext7-core:7.1.13' // add this library
    }
    

    AndroidManifest

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

    PermissionChecker

    public class PermissionsChecker {
    
        /**
         * Permission List
         */
        public static String[] REQUIRED_PERMISSION = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
    
        /**
         * Context
         */
        private final Context context;
    
        public PermissionsChecker(Context context) {
            this.context = context;
        }
    
        public boolean lacksPermissions(String... permissions) {
            for (String permission : permissions) {
                if (lacksPermission(permission)) {
                    return true;
                }
            }
            return false;
        }
    
        private boolean lacksPermission(String permission) {
            return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_DENIED;
        }
    }
    

    PermissionActivity

    public class PermissionsActivity extends AppCompatActivity {
    
        public static final int PERMISSIONS_GRANTED = 0;
        public static final int PERMISSIONS_DENIED = 1;
    
        public static final int PERMISSION_REQUEST_CODE = 0;
    
        private static final String EXTRA_PERMISSIONS = "com.koops.sales.EXTRA_PERMISSIONS";
        private static final String PACKAGE_URL_SCHEME = "package:";
    
        private PermissionsChecker checker;
        private boolean requiresCheck;
    
        public static void startActivityForResult(@NonNull Activity activity, int requestCode, String... permissions) {
            Intent intent = new Intent(activity, PermissionsActivity.class);
            intent.putExtra(EXTRA_PERMISSIONS, permissions);
            ActivityCompat.startActivityForResult(activity, intent, requestCode, null);
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            if (getIntent() == null || !getIntent().hasExtra(EXTRA_PERMISSIONS)) {
                throw new RuntimeException("This Activity needs to be launched using the static startActivityForResult() method.");
            }
            //setContentView(R.layout.activity_permissions);
    
            checker = new PermissionsChecker(this);
            requiresCheck = true;
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            if (requiresCheck) {
                String[] permissions = getPermissions();
    
                if (checker.lacksPermissions(permissions)) {
                    requestPermissions(permissions);
                } else {
                    allPermissionsGranted();
                }
            } else {
                requiresCheck = true;
            }
        }
    
        private String[] getPermissions() {
            return getIntent().getStringArrayExtra(EXTRA_PERMISSIONS);
        }
    
        private void requestPermissions(@NonNull String... permissions) {
            ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE);
        }
    
        private void allPermissionsGranted() {
            setResult(PERMISSIONS_GRANTED);
            finish();
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            if (requestCode == PERMISSION_REQUEST_CODE && hasAllPermissionsGranted(grantResults)) {
                requiresCheck = true;
                allPermissionsGranted();
            } else {
                requiresCheck = false;
                showMissingPermissionDialog();
            }
        }
    
        private boolean hasAllPermissionsGranted(@NonNull int[] grantResults) {
            for (int grantResult : grantResults) {
                if (grantResult == PackageManager.PERMISSION_DENIED) {
                    return false;
                }
            }
            return true;
        }
    
        private void showMissingPermissionDialog() {
            AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(PermissionsActivity.this);
            dialogBuilder.setTitle(R.string.string_permission_help);
            dialogBuilder.setMessage(R.string.string_permission_help_text);
            dialogBuilder.setNegativeButton(R.string.string_permission_quit, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    setResult(PERMISSIONS_DENIED);
                    finish();
                }
            });
            dialogBuilder.setPositiveButton(R.string.string_settings, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    startAppSettings();
                }
            });
            dialogBuilder.show();
        }
    
        private void startAppSettings() {
            Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            intent.setData(Uri.parse(PACKAGE_URL_SCHEME + getPackageName()));
            startActivity(intent);
        }
    }
    

    Main Activity

    import com.myapplication.R;
    import com.myapplication.PermissionsActivity;
    import com.myapplication.PermissionsChecker;
    ....
    
    import static com.myapplication.permission.PermissionsActivity.PERMISSION_REQUEST_CODE;
    import static com.myapplication.PermissionsChecker.REQUIRED_PERMISSION;
    
    public class MainActivity extends AppCompatActivity {
       PermissionChecker checker;
    
       @Override
       protected void onCreate(Bundle savedInstanceState) {
          ...
    
          String dest = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString() + "/test.pdf";
          checker = new PermissionsChecker(this);
          if (checker.lacksPermissions(REQUIRED_PERMISSION)) {
             PermissionsActivity.startActivityForResult(MainActivity.this, PERMISSION_REQUEST_CODE, REQUIRED_PERMISSION);
        } else {
            generatePDF(dest);
        }
      }
    
      private void generatePDF(String dest) {
          WriterProperties writerProperties = new WriterProperties();
          writerProperties.setStandardEncryption("1234".getBytes(), "1234".getBytes(), EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_128);
          PdfWriter pdfWriter = new PdfWriter(new FileOutputStream(dest), writerProperties);
          PdfDocument pdfDocument = new PdfDocument(pdfWriter);
          Document document = new Document(pdfDocument, PageSize.A4, true);
    
       // Init pdf property for writing
          Color mColorAccent = new DeviceRgb(153, 204, 255);
          Color mColorBlack = new DeviceRgb(0, 0, 0);
          float mHeadingFontSize = 20.0f;
          float mValueFontSize = 26.0f;
    
          PdfFont font = PdfFontFactory.createFont("assets/fonts/brandon_medium.otf", "UTF-8", true);
    
          Text mOrderIdValueChunk = new Text("#Example pdf password").setFont(font).setFontSize(mValueFontSize).setFontColor(mColorBlack);
          Paragraph mOrderIdValueParagraph = new Paragraph(mOrderIdValueChunk);
          document.add(mOrderIdValueParagraph);
           
          document.close();
          Toast.makeText(mContext, "Pdf successfully created with password :)", Toast.LENGTH_SHORT).show();
    
           } catch (IOException e) {
               Log.e("TAG", e.getLocalizedMessage());
           } catch (ActivityNotFoundException eActivity) {
               Toast.makeText(mContext, "No application found to open this file.", Toast.LENGTH_SHORT).show();
           }
       }
    
       @Override
       protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == PermissionsActivity.PERMISSIONS_GRANTED) {
            Toast.makeText(mContext, "Permission Granted to Save", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(mContext, "Permission not granted, Try again!", Toast.LENGTH_SHORT).show();
        }
    
      // to open pdf file
      private void openPDF(String dest) {
          new Handler().postDelayed(new Runnable() {
              @Override
              public void run() {
                  try {
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    Uri uri = Uri.fromFile(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) +
                            "/" + dest));
                    intent.setDataAndType(uri, "application/pdf");
                    StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
                    StrictMode.setVmPolicy(builder.build());
                    intent = Intent.createChooser(intent, "Open File");
                    intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
                    startActivity(intent);
                  } catch (Exception e) {
                      Log.d("TAG", "run: Error");
                  }
              }
          }, 1000);
      }
    }
    

    Conclusion

    The main part to set password for pdf file is using WriterProperties as second parameter of PdfWriter object.

    WriterProperties writerProperties = new WriterProperties();
    writerProperties.setStandardEncryption("1234".getBytes(), "1234".getBytes(), EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_128);
    
    PdfWriter pdfWriter = new PdfWriter(new FileOutputStream(dest), writerProperties);