Browse Source

PDFTool(Android) - 数字签名功能

liuxiaolong 1 year ago
parent
commit
c270030c2e
84 changed files with 1731 additions and 901 deletions
  1. 0 3
      Annotations/build.gradle
  2. 33 43
      Annotations/src/main/java/com/compdfkit/annotations/PDFAnnotationSampleActivity.java
  3. BIN
      ComPDFKit_Repo/compdfkit/ComPDFKit.aar
  4. 3 5
      ComPDFKit_Tools/build.gradle
  5. 0 2
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/annotation/pdfproperties/pdfsignature/CAddSignatureActivity.java
  6. 5 30
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/activity/CBasicActivity.java
  7. 44 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/basic/activity/CPermissionActivity.java
  8. 89 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/basic/fragment/CBasicBottomSheetDialogFragment.java
  9. 51 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/basic/fragment/CPermissionFragment.java
  10. 0 2
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/contextmenu/impl/CEditImageContextMenuView.java
  11. 31 2
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/CPermissionUtil.java
  12. 33 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/activitycontracts/BaseActivityResultLauncher.java
  13. 0 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/activitycontracts/CImageResultContracts.java
  14. 14 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/activitycontracts/CMultiplePermissionResultLauncher.java
  15. 18 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/activitycontracts/CPermissionResultLauncher.java
  16. 25 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/activitycontracts/CSelectPDFDocumentResultContract.java
  17. 15 4
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/date/CDateUtil.java
  18. 0 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/image/CBitmapUtil.java
  19. 0 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/window/CModeSwitchDialogFragment.java
  20. 0 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/views/pdfproperties/pdfstyle/CAnnotStyle.java
  21. 0 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/views/pdfproperties/stamp/CPDFStampTextView.java
  22. 0 4
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/views/pdfview/CPDFViewCtrl.java
  23. 0 4
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/contenteditor/pdfproperties/CEditImagePropertiesFragment.java
  24. 0 3
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/forms/pdfformbar/CFormToolbar.java
  25. 0 4
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/forms/pdfproperties/pdfsign/CustomSignatureWidgetImpl.java
  26. 3 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/CSignatureToolBar.java
  27. 207 84
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/CertificateDigitalDatas.java
  28. 20 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/SignatureStatus.java
  29. 64 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/bean/CPDFCertAttrDataItem.java
  30. 93 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/bean/CPDFOwnerItemData.java
  31. 8 7
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/bean/CPDFSignatureItemData.java
  32. 27 22
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/importcert/create/CImportCertificateDigitalDialog.java
  33. 1 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/importcert/create/CPDFSelectDigitalSignatureDialog.java
  34. 0 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/importcert/create/CountryReginSpinnerAdapter.java
  35. 19 16
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/importcert/create/CreateCertificateDigitalDialog.java
  36. 129 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/CertAttrDatas.java
  37. 57 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/CertAttrListAdapter.java
  38. 71 25
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/CertDetailsDialog.java
  39. 102 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/CertDetailsListAdapter.java
  40. 56 35
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/CertDigitalSignAttributesDialog.java
  41. 39 26
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/CertDigitalSignInfoDialog.java
  42. 26 22
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/signlist/CPDFCertDigitalSignListDialog.java
  43. 19 13
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/signlist/adapter/CertDigitalSignListAdapter.java
  44. 3 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/pdfproperties/pdfsign/CDigitalSignStyleData.java
  45. 3 6
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/pdfproperties/pdfsign/CDigitalSignatureWidgetImpl.java
  46. 32 28
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/preview/CDigitalSignStylePreviewDialog.java
  47. 0 5
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/preview/view/CSignStylePositionView.java
  48. 0 2
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/preview/view/CSignStyleReasonView.java
  49. 7 16
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/verify/view/CVerifySignStatusView.java
  50. 10 0
      ComPDFKit_Tools/src/main/res/drawable-night/tools_ic_digital_signature.xml
  51. 0 1
      ComPDFKit_Tools/src/main/res/layout-land/tools_sign_style_preview_main.xml
  52. 7 243
      ComPDFKit_Tools/src/main/res/layout/tools_sign_certificate_attributes_fragment.xml
  53. 25 0
      ComPDFKit_Tools/src/main/res/layout/tools_sign_certificate_attributes_list_head_item.xml
  54. 47 0
      ComPDFKit_Tools/src/main/res/layout/tools_sign_certificate_attributes_list_item.xml
  55. 29 0
      ComPDFKit_Tools/src/main/res/layout/tools_sign_certificate_details_dialog.xml
  56. 45 0
      ComPDFKit_Tools/src/main/res/layout/tools_sign_certificate_details_list_item.xml
  57. 1 0
      ComPDFKit_Tools/src/main/res/layout/tools_sign_certificate_digital_sign_info_fragment.xml
  58. 0 1
      ComPDFKit_Tools/src/main/res/layout/tools_sign_create_cert_digital_id_fragment.xml
  59. 0 1
      ComPDFKit_Tools/src/main/res/layout/tools_sign_create_cert_digital_id_info_layout.xml
  60. 0 1
      ComPDFKit_Tools/src/main/res/layout/tools_sign_style_preview_dialog.xml
  61. 0 1
      ComPDFKit_Tools/src/main/res/layout/tools_sign_style_preview_main.xml
  62. 1 1
      ComPDFKit_Tools/src/main/res/layout/tools_sign_verify_sign_status_view.xml
  63. 26 3
      ComPDFKit_Tools/src/main/res/values/tools_strings.xml
  64. 0 1
      ContentEditor/build.gradle
  65. 23 34
      ContentEditor/src/main/java/com/compdfkit/contenteditor/PDFEditSampleActivity.java
  66. 2 3
      DigitalSignature/build.gradle
  67. 3 3
      DigitalSignature/src/androidTest/java/com/compdfkit/digitalsignature/ExampleInstrumentedTest.java
  68. BIN
      DigitalSignature/src/main/assets/4KDAN_adobe + chunghwa.pdf
  69. BIN
      DigitalSignature/src/main/assets/PDF32000_2008(2).pdf
  70. BIN
      DigitalSignature/src/main/assets/PSPDFKit_Widget_2_Widget.pdf
  71. BIN
      DigitalSignature/src/main/assets/測試樣張01_Signed拷貝.pdf
  72. 5 5
      DigitalSignature/src/main/java/com/compdfkit/digitalsignature/CViewerScreenStatusManager.java
  73. 62 41
      DigitalSignature/src/main/java/com/compdfkit/digitalsignature/PDFSignaturesSampleActivity.java
  74. 1 1
      DigitalSignature/src/main/res/values-night/themes.xml
  75. 2 2
      DigitalSignature/src/test/java/com/compdfkit/digitalsignature/ExampleUnitTest.java
  76. 0 1
      DocsEditor/build.gradle
  77. 22 27
      DocsEditor/src/main/java/com/compdfkit/docseditor/MainActivity.java
  78. 0 1
      Forms/build.gradle
  79. 23 26
      Forms/src/main/java/com/compdfkit/forms/PDFFormSampleActivity.java
  80. 0 1
      PDFViewer/build.gradle
  81. 36 54
      PDFViewer/src/main/java/com/compdfkit/pdfviewer/MainActivity.java
  82. 0 1
      Samples/src/main/java/com/compdfkit/samples/util/FileUtils.java
  83. 0 3
      Viewer/build.gradle
  84. 14 24
      Viewer/src/main/java/com/compdfkit/viewer/PDFViewerSampleActivity.java

+ 0 - 3
Annotations/build.gradle

@@ -52,7 +52,4 @@ dependencies {
     implementation 'com.google.android.material:material:1.8.0'
     implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
     implementation project(':ComPDFKit_Tools')
-
-    implementation 'pub.devrel:easypermissions:3.0.0'
-
 }

+ 33 - 43
Annotations/src/main/java/com/compdfkit/annotations/PDFAnnotationSampleActivity.java

@@ -5,17 +5,17 @@ import android.content.Intent;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.view.View;
 
 import androidx.activity.result.ActivityResultLauncher;
 import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
 
 import com.compdfkit.annotations.databinding.AnnotationPdfSampleActivityBinding;
 import com.compdfkit.core.annotation.CPDFAnnotation;
-import com.compdfkit.tools.common.activity.CBasicActivity;
+import com.compdfkit.tools.common.basic.activity.CBasicPDFActivity;
 import com.compdfkit.tools.common.utils.CFileUtils;
+import com.compdfkit.tools.common.utils.CPermissionUtil;
+import com.compdfkit.tools.common.utils.activitycontracts.CSelectPDFDocumentResultContract;
 import com.compdfkit.tools.common.utils.dialog.CAlertDialog;
 import com.compdfkit.tools.common.utils.task.CExtractAssetFileTask;
 import com.compdfkit.tools.common.utils.window.CPopupMenuWindow;
@@ -28,12 +28,9 @@ import com.compdfkit.tools.viewer.pdfsearch.CSearchResultDialogFragment;
 import com.compdfkit.ui.reader.CPDFReaderView;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 
-import pub.devrel.easypermissions.AppSettingsDialog;
-import pub.devrel.easypermissions.EasyPermissions;
 
-public class PDFAnnotationSampleActivity extends CBasicActivity {
+public class PDFAnnotationSampleActivity extends CBasicPDFActivity {
 
     /**
      * assets folder pdf file
@@ -44,9 +41,8 @@ public class PDFAnnotationSampleActivity extends CBasicActivity {
 
     CAnnotSampleScreenManager screenManager = new CAnnotSampleScreenManager();
 
-    private ActivityResultLauncher<Intent> selectDocumentLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
-        if (result.getData() != null && result.getData().getData() != null) {
-            Uri uri = result.getData().getData();
+    private ActivityResultLauncher<Void> selectDocumentLauncher = registerForActivityResult(new CSelectPDFDocumentResultContract(), uri -> {
+        if (uri != null) {
             CFileUtils.takeUriPermission(this, uri);
             binding.pdfView.resetAnnotationType();
             binding.pdfView.openPDF(uri);
@@ -154,7 +150,7 @@ public class PDFAnnotationSampleActivity extends CBasicActivity {
                 sharePDF(binding.pdfView);
             });
             menuWindow.addItem(R.drawable.tools_ic_new_file, R.string.tools_open_document, v1 -> {
-                if (hasStoragePermissions(STORAGE_PERMISSIONS)) {
+                if (CPermissionUtil.hasStoragePermissions(this)) {
                     selectDocument();
                 } else {
                     requestStoragePermissions();
@@ -167,9 +163,17 @@ public class PDFAnnotationSampleActivity extends CBasicActivity {
 
     private void requestStoragePermissions() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
-            startActivity(new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION));
+            CPermissionUtil.openManageAllFileAppSettings(this);
         } else {
-            EasyPermissions.requestPermissions(this, "request permission", REQUEST_EXTERNAL_PERMISSION, STORAGE_PERMISSIONS);
+            multiplePermissionResultLauncher.launch(STORAGE_PERMISSIONS, result -> {
+                if (CPermissionUtil.hasStoragePermissions(this)) {
+                    selectDocument();
+                }else {
+                    if (!CPermissionUtil.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)){
+                        showPermissionsRequiredDialog();
+                    }
+                }
+            });
         }
     }
 
@@ -180,8 +184,15 @@ public class PDFAnnotationSampleActivity extends CBasicActivity {
             screenManager.changeWindowStatus(type);
             //You are required to grant recording permission when selecting voice notes
             if (type == CAnnotationType.SOUND) {
-                if (!EasyPermissions.hasPermissions(this, Manifest.permission.RECORD_AUDIO)) {
-                    EasyPermissions.requestPermissions(this, getString(R.string.tools_use_sound_annot), 111, Manifest.permission.RECORD_AUDIO);
+                if (!hasPermission(Manifest.permission.RECORD_AUDIO)) {
+                    permissionResultLauncher.launch(Manifest.permission.RECORD_AUDIO, hasRecordAudioPermission -> {
+                        if (!hasRecordAudioPermission){
+                            binding.pdfView.resetAnnotationType();
+                            if (!CPermissionUtil.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)){
+                                showPermissionsRequiredDialog();
+                            }
+                        }
+                    });
                 }
             }
         });
@@ -189,6 +200,8 @@ public class PDFAnnotationSampleActivity extends CBasicActivity {
         binding.inkCtrlView.setFragmentManager(getSupportFragmentManager());
     }
 
+
+
     private void initSearchBar() {
         binding.pdfSearchToolBar.initWithPDFView(binding.pdfView);
         binding.pdfSearchToolBar.onSearchQueryResults(list -> {
@@ -209,11 +222,11 @@ public class PDFAnnotationSampleActivity extends CBasicActivity {
 
     private void selectDocument() {
         if (binding.pdfView.getCPdfReaderView().getPDFDocument() == null){
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+            selectDocumentLauncher.launch(null);
             return;
         }
         if (!binding.pdfView.getCPdfReaderView().getPDFDocument().hasChanges()) {
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+            selectDocumentLauncher.launch(null);
             return;
         }
         CAlertDialog alertDialog = CAlertDialog.newInstance(getString(com.compdfkit.tools.R.string.tools_save_title), getString(com.compdfkit.tools.R.string.tools_save_message));
@@ -221,42 +234,19 @@ public class PDFAnnotationSampleActivity extends CBasicActivity {
             //save pdf document
             binding.pdfView.savePDF((filePath, pdfUri) -> {
                 alertDialog.dismiss();
-                selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+                selectDocumentLauncher.launch(null);
             }, e -> {
                 alertDialog.dismiss();
-                selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+                selectDocumentLauncher.launch(null);
             });
         });
         alertDialog.setCancelClickListener(v -> {
             alertDialog.dismiss();
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+            selectDocumentLauncher.launch(null);
         });
         alertDialog.show(getSupportFragmentManager(), "alertDialog");
     }
 
-    @Override
-    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
-        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
-        if (requestCode == REQUEST_EXTERNAL_PERMISSION) {
-            if (EasyPermissions.hasPermissions(this, STORAGE_PERMISSIONS)) {
-                selectDocument();
-            }
-        } else if (requestCode == 111) {
-            if (!EasyPermissions.hasPermissions(this, permissions)) {
-                if (EasyPermissions.somePermissionPermanentlyDenied(this, Arrays.asList(permissions))) {
-                    new AppSettingsDialog.Builder(this)
-                            .build().show();
-                } else {
-                    binding.pdfView.resetAnnotationType();
-                }
-            }
-        } else if (requestCode == AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE) {
-            if (EasyPermissions.hasPermissions(this, permissions)) {
-
-            }
-        }
-    }
-
     @Override
     public void onBackPressed() {
         if (binding.pdfView != null) {

BIN
ComPDFKit_Repo/compdfkit/ComPDFKit.aar


+ 3 - 5
ComPDFKit_Tools/build.gradle

@@ -47,9 +47,7 @@ dependencies {
     api 'com.github.bumptech.glide:glide:4.15.1'
     annotationProcessor 'com.github.bumptech.glide:compiler:4.15.1'
     api 'androidx.documentfile:documentfile:1.0.1'
-
-    implementation 'androidx.appcompat:appcompat:1.6.1'
-    implementation 'com.google.android.material:material:1.8.0'
-    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
-    implementation 'com.google.android.flexbox:flexbox:3.0.0'
+    api 'androidx.appcompat:appcompat:1.6.1'
+    api 'com.google.android.material:material:1.8.0'
+    api 'androidx.constraintlayout:constraintlayout:2.1.4'
 }

+ 0 - 2
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/annotation/pdfproperties/pdfsignature/CAddSignatureActivity.java

@@ -32,8 +32,6 @@ import com.bumptech.glide.Glide;
 import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
 import com.compdfkit.tools.R;
 import com.compdfkit.tools.annotation.pdfproperties.pdfsignature.data.CSignatureDatas;
-import com.compdfkit.tools.common.utils.CLog;
-import com.compdfkit.tools.common.utils.CToastUtil;
 import com.compdfkit.tools.common.utils.activitycontracts.CImageResultContracts;
 import com.compdfkit.tools.common.utils.dialog.CImportImageDialogFragment;
 import com.compdfkit.tools.common.utils.image.CBitmapUtil;

+ 5 - 30
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/activity/CBasicActivity.java

@@ -7,18 +7,14 @@
  * This notice may not be removed from this file.
  */
 
-package com.compdfkit.tools.common.activity;
+package com.compdfkit.tools.common.basic.activity;
 
 
-import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.graphics.Color;
 import android.os.Build;
 import android.os.Environment;
-import android.provider.Settings;
 import android.text.TextUtils;
 
-import androidx.appcompat.app.AppCompatActivity;
 import androidx.core.content.ContextCompat;
 
 import com.compdfkit.core.annotation.CPDFLineAnnotation;
@@ -39,6 +35,7 @@ import com.compdfkit.tools.common.contextmenu.impl.CEditImageContextMenuView;
 import com.compdfkit.tools.common.contextmenu.impl.CEditTextContextMenuView;
 import com.compdfkit.tools.common.contextmenu.impl.CSignatureContextMenuView;
 import com.compdfkit.tools.common.utils.CFileUtils;
+import com.compdfkit.tools.common.utils.CPermissionUtil;
 import com.compdfkit.tools.common.views.pdfproperties.pdfstyle.CStyleType;
 import com.compdfkit.tools.common.views.pdfproperties.pdfstyle.manager.CStyleManager;
 import com.compdfkit.tools.common.views.pdfview.CPDFViewCtrl;
@@ -54,30 +51,11 @@ import com.compdfkit.tools.viewer.pdfinfo.CPDFDocumentInfoDialogFragment;
 
 import java.io.File;
 
-public class CBasicActivity extends AppCompatActivity {
+public class CBasicPDFActivity extends CPermissionActivity {
 
     protected static final int REQUEST_EXTERNAL_PERMISSION = 1233;
 
-    public final static String[] STORAGE_PERMISSIONS = new String[]{
-            android.Manifest.permission.READ_EXTERNAL_STORAGE,
-            android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
-    };
-
-    public boolean hasStoragePermissions(String... perms) {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
-            return true;
-        }
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
-            return Environment.isExternalStorageManager();
-        }
-        for (String perm : perms) {
-            if (ContextCompat.checkSelfPermission(this, perm)
-                    != PackageManager.PERMISSION_GRANTED) {
-                return false;
-            }
-        }
-        return true;
-    }
+    protected int curEditMode = CPDFEditPage.LoadUnknown;
 
     protected void resetContextMenu(CPDFViewCtrl pdfView, CPreviewMode mode) {
         switch (mode) {
@@ -186,7 +164,7 @@ public class CBasicActivity extends AppCompatActivity {
                 document.getAbsolutePath().startsWith("/storage/emulated/0");
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && isExternalFile) {
             if (!Environment.isExternalStorageManager()) {
-                startActivity(new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION));
+                CPermissionUtil.openManageAllFileAppSettings(this);
                 return;
             }
         }
@@ -205,9 +183,6 @@ public class CBasicActivity extends AppCompatActivity {
         });
     }
 
-    protected int curEditMode = CPDFEditPage.LoadUnknown;
-
-
     protected void showPageEdit(CPDFViewCtrl pdfView, boolean enterEdit, CPDFPageEditDialogFragment.OnBackLisener backListener) {
         curEditMode = pdfView.getCPdfReaderView().getLoadType();
         pdfView.exitEditMode();

+ 44 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/basic/activity/CPermissionActivity.java

@@ -0,0 +1,44 @@
+package com.compdfkit.tools.common.basic.activity;
+
+
+import android.content.pm.PackageManager;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.content.ContextCompat;
+
+import com.compdfkit.tools.R;
+import com.compdfkit.tools.common.utils.CPermissionUtil;
+import com.compdfkit.tools.common.utils.activitycontracts.CMultiplePermissionResultLauncher;
+import com.compdfkit.tools.common.utils.activitycontracts.CPermissionResultLauncher;
+import com.compdfkit.tools.common.utils.dialog.CAlertDialog;
+
+
+public class CPermissionActivity extends AppCompatActivity {
+
+    protected final static String[] STORAGE_PERMISSIONS = CPermissionUtil.STORAGE_PERMISSIONS;
+
+    protected CPermissionResultLauncher permissionResultLauncher = new CPermissionResultLauncher(this);
+
+    protected CMultiplePermissionResultLauncher multiplePermissionResultLauncher = new CMultiplePermissionResultLauncher(this);
+
+    public boolean hasPermission(String permission){
+        return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED;
+    }
+
+    protected void showPermissionsRequiredDialog(){
+        CAlertDialog alertDialog = CAlertDialog.newInstance(getString(R.string.tools_permission_tips_title), getString(R.string.tools_permission_tips_msg));
+        alertDialog.setCancelable(false);
+        alertDialog.setConfirmClickListener(v -> {
+            toSelfSetting();
+            alertDialog.dismiss();
+        });
+        alertDialog.setCancelClickListener(v -> alertDialog.dismiss());
+        alertDialog.show(getSupportFragmentManager(), "permissionRequiredDialog");
+    }
+
+    protected void toSelfSetting(){
+        CPermissionUtil.toSelfSetting(this);
+    }
+}
+
+

+ 89 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/basic/fragment/CBasicBottomSheetDialogFragment.java

@@ -0,0 +1,89 @@
+/**
+ * Copyright © 2014-2023 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
+package com.compdfkit.tools.common.basic.fragment;
+
+
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.compdfkit.tools.R;
+import com.compdfkit.tools.common.utils.dialog.CDialogFragmentUtil;
+import com.compdfkit.tools.common.utils.viewutils.CViewUtils;
+import com.google.android.material.bottomsheet.BottomSheetBehavior;
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
+
+public abstract class CBasicBottomSheetDialogFragment extends BottomSheetDialogFragment {
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setStyle(STYLE_NORMAL, getStyle());
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        BottomSheetBehavior<View> behavior = BottomSheetBehavior.from((View) getView().getParent());
+        if (fullScreen()) {
+            CDialogFragmentUtil.setBottomSheetDialogFragmentFullScreen(getDialog(), behavior);
+        }
+        CDialogFragmentUtil.setDimAmount(getDialog(), dimAmount());
+        behavior.setDraggable(draggable());
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+        View view = inflater.inflate(layoutId(), container, false);
+        onCreateView(view);
+        return view;
+    }
+
+    @Override
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        onViewCreate();
+    }
+
+    protected abstract @LayoutRes int layoutId();
+
+    protected int getStyle(){
+        return R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle;
+    }
+
+    protected boolean fullScreen(){
+        return false;
+    }
+
+    protected float dimAmount(){
+        return 0.2F;
+    }
+
+    protected boolean draggable(){
+        return true;
+    }
+
+    protected abstract void onCreateView(View rootView);
+
+    protected abstract void onViewCreate();
+
+    @Override
+    public void onConfigurationChanged(@NonNull Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        CDialogFragmentUtil.setDimAmount(getDialog(), dimAmount());
+    }
+}

+ 51 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/basic/fragment/CPermissionFragment.java

@@ -0,0 +1,51 @@
+/**
+ * Copyright © 2014-2023 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
+package com.compdfkit.tools.common.basic.fragment;
+
+import android.content.pm.PackageManager;
+
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
+
+import com.compdfkit.tools.R;
+import com.compdfkit.tools.common.utils.CPermissionUtil;
+import com.compdfkit.tools.common.utils.activitycontracts.CMultiplePermissionResultLauncher;
+import com.compdfkit.tools.common.utils.activitycontracts.CPermissionResultLauncher;
+import com.compdfkit.tools.common.utils.dialog.CAlertDialog;
+
+
+public class CPermissionFragment extends Fragment {
+
+    protected final static String[] STORAGE_PERMISSIONS = CPermissionUtil.STORAGE_PERMISSIONS;
+
+    protected CPermissionResultLauncher permissionResultLauncher = new CPermissionResultLauncher(this);
+
+    protected CMultiplePermissionResultLauncher multiplePermissionResultLauncher = new CMultiplePermissionResultLauncher(this);
+
+    public boolean hasPermission(String permission){
+        return ContextCompat.checkSelfPermission(getContext(), permission) == PackageManager.PERMISSION_GRANTED;
+    }
+
+    protected void showPermissionsRequiredDialog(){
+        CAlertDialog alertDialog = CAlertDialog.newInstance(getString(R.string.tools_permission_tips_title), getString(R.string.tools_permission_tips_msg));
+        alertDialog.setCancelable(false);
+        alertDialog.setConfirmClickListener(v -> {
+            toSelfSetting();
+            alertDialog.dismiss();
+        });
+        alertDialog.setCancelClickListener(v -> alertDialog.dismiss());
+        alertDialog.show(getChildFragmentManager(), "permissionRequiredDialog");
+    }
+
+    protected void toSelfSetting(){
+        CPermissionUtil.toSelfSetting(getContext());
+    }
+
+}

+ 0 - 2
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/contextmenu/impl/CEditImageContextMenuView.java

@@ -13,14 +13,12 @@ import android.widget.Toast;
 
 import androidx.fragment.app.FragmentActivity;
 
-import com.compdfkit.core.document.CPDFSdk;
 import com.compdfkit.tools.R;
 import com.compdfkit.tools.common.contextmenu.CPDFContextMenuHelper;
 import com.compdfkit.tools.common.contextmenu.interfaces.ContextMenuEditImageProvider;
 import com.compdfkit.tools.common.contextmenu.provider.ContextMenuMultipleLineView;
 import com.compdfkit.tools.common.contextmenu.provider.ContextMenuView;
 import com.compdfkit.tools.common.utils.CToastUtil;
-import com.compdfkit.tools.common.utils.image.CBitmapUtil;
 import com.compdfkit.tools.common.views.pdfproperties.pdfstyle.CAnnotStyle;
 import com.compdfkit.tools.common.views.pdfproperties.pdfstyle.CStyleDialogFragment;
 import com.compdfkit.tools.common.views.pdfproperties.pdfstyle.CStyleType;

+ 31 - 2
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/CPermissionUtil.java

@@ -10,13 +10,16 @@
 package com.compdfkit.tools.common.utils;
 
 
+import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.net.Uri;
 import android.os.Build;
 import android.os.Environment;
 import android.provider.Settings;
 
+import androidx.core.app.ActivityCompat;
 import androidx.core.content.ContextCompat;
 
 public class CPermissionUtil {
@@ -42,8 +45,34 @@ public class CPermissionUtil {
         return true;
     }
 
-    public static void openAppSettings(Context context){
-        context.startActivity(new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION));
+    public static void openManageAllFileAppSettings(Context context){
+        try{
+            Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION, Uri.parse("package:"+context.getPackageName()));
+            context.startActivity(intent);
+        }catch (Exception e){
+            Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
+            context.startActivity(intent);
+        }
+    }
+
+    public static void toSelfSetting(Context context) {
+        Intent mIntent = new Intent();
+        mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        if (Build.VERSION.SDK_INT >= 9) {
+            mIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
+            mIntent.setData(Uri.fromParts("package", context.getPackageName(), null));
+        } else if (Build.VERSION.SDK_INT <= 8) {
+            mIntent.setAction(Intent.ACTION_VIEW);
+            mIntent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");
+            mIntent.putExtra("com.android.settings.ApplicationPkgName", context.getPackageName());
+        }
+        context.startActivity(mIntent);
     }
 
+    public static boolean shouldShowRequestPermissionRationale(Activity activity, String permission){
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M){
+            return true;
+        }
+        return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);
+    }
 }

+ 33 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/activitycontracts/BaseActivityResultLauncher.java

@@ -0,0 +1,33 @@
+package com.compdfkit.tools.common.utils.activitycontracts;
+
+import androidx.activity.result.ActivityResultCallback;
+import androidx.activity.result.ActivityResultCaller;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContract;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+public class BaseActivityResultLauncher<I, O> {
+
+    private final ActivityResultLauncher<I> launcher;
+    private ActivityResultCallback<O> callback;
+
+    public BaseActivityResultLauncher(@NonNull ActivityResultCaller caller,
+                                      @NonNull ActivityResultContract<I, O> contract) {
+        launcher = caller.registerForActivityResult(contract, result -> {
+            if (callback != null) {
+                callback.onActivityResult(result);
+                callback = null;
+            }
+        });
+    }
+
+    public void launch(@Nullable I input, @NonNull ActivityResultCallback<O> callback) {
+        this.callback = callback;
+        launcher.launch(input);
+    }
+
+    public void launch(@Nullable I input) {
+        launcher.launch(input);
+    }
+}

+ 0 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/activitycontracts/CImageResultContracts.java

@@ -26,7 +26,6 @@ import com.compdfkit.tools.common.utils.date.CDateUtil;
 
 import java.io.File;
 
-
 public class CImageResultContracts extends ActivityResultContract<CImageResultContracts.RequestType, Uri> {
 
     public enum RequestType {

+ 14 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/activitycontracts/CMultiplePermissionResultLauncher.java

@@ -0,0 +1,14 @@
+package com.compdfkit.tools.common.utils.activitycontracts;
+
+import androidx.activity.result.ActivityResultCaller;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.annotation.NonNull;
+
+import java.util.Map;
+
+public class CMultiplePermissionResultLauncher extends BaseActivityResultLauncher<String[], Map<String, Boolean>> {
+
+    public CMultiplePermissionResultLauncher(@NonNull ActivityResultCaller caller) {
+        super(caller, new ActivityResultContracts.RequestMultiplePermissions());
+    }
+}

+ 18 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/activitycontracts/CPermissionResultLauncher.java

@@ -0,0 +1,18 @@
+package com.compdfkit.tools.common.utils.activitycontracts;
+
+import androidx.activity.result.ActivityResultCaller;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.annotation.NonNull;
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2023/8/30
+ * description:
+ */
+public class CPermissionResultLauncher extends BaseActivityResultLauncher<String, Boolean>{
+    public CPermissionResultLauncher(@NonNull ActivityResultCaller caller) {
+        super(caller, new ActivityResultContracts.RequestPermission());
+    }
+}
+

+ 25 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/activitycontracts/CSelectPDFDocumentResultContract.java

@@ -0,0 +1,25 @@
+package com.compdfkit.tools.common.utils.activitycontracts;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import androidx.activity.result.contract.ActivityResultContract;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.compdfkit.tools.common.utils.CFileUtils;
+
+
+public class CSelectPDFDocumentResultContract extends ActivityResultContract<Void, Uri> {
+    @NonNull
+    @Override
+    public Intent createIntent(@NonNull Context context, Void unused) {
+        return CFileUtils.getContentIntent();
+    }
+
+    @Override
+    public Uri parseResult(int i, @Nullable Intent intent) {
+        return intent != null ? intent.getData() : null;
+    }
+}

+ 15 - 4
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/date/CDateUtil.java

@@ -2,12 +2,9 @@ package com.compdfkit.tools.common.utils.date;
 
 
 import android.text.TextUtils;
-import android.text.format.DateUtils;
 
+import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.time.ZoneId;
-import java.time.ZoneOffset;
-import java.util.Calendar;
 import java.util.Date;
 import java.util.TimeZone;
 
@@ -44,4 +41,18 @@ public class CDateUtil {
         return df.format(new Date());
     }
 
+    public static String formatPDFUTCDate(String pdfUTCDate){
+        SimpleDateFormat inputFormat = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
+        inputFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+        SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        try {
+            Date date = inputFormat.parse(pdfUTCDate);
+            String formattedOutput = outputFormat.format(date);
+            return formattedOutput;
+        } catch (ParseException e) {
+            e.printStackTrace();
+            return pdfUTCDate;
+        }
+    }
+
 }

+ 0 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/image/CBitmapUtil.java

@@ -19,7 +19,6 @@ import com.compdfkit.tools.common.utils.CUriUtil;
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 
 public class CBitmapUtil {

+ 0 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/window/CModeSwitchDialogFragment.java

@@ -1,7 +1,6 @@
 package com.compdfkit.tools.common.utils.window;
 
 
-import android.graphics.Paint;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;

+ 0 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/views/pdfproperties/pdfstyle/CAnnotStyle.java

@@ -30,7 +30,6 @@ import com.compdfkit.tools.common.utils.CLog;
 
 import java.io.Serializable;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 public class CAnnotStyle implements Serializable {

+ 0 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/views/pdfproperties/stamp/CPDFStampTextView.java

@@ -12,7 +12,6 @@ import android.graphics.Shader;
 import android.text.Layout;
 import android.text.TextPaint;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.View;
 
 import androidx.annotation.Nullable;

+ 0 - 4
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/views/pdfview/CPDFViewCtrl.java

@@ -11,15 +11,11 @@ package com.compdfkit.tools.common.views.pdfview;
 
 import android.animation.ObjectAnimator;
 import android.content.Context;
-import android.content.Intent;
 import android.content.res.TypedArray;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
-import android.provider.Settings;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.LinearLayout;

+ 0 - 4
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/contenteditor/pdfproperties/CEditImagePropertiesFragment.java

@@ -22,9 +22,7 @@ import androidx.appcompat.widget.AppCompatImageView;
 import androidx.constraintlayout.widget.ConstraintLayout;
 
 import com.compdfkit.tools.R;
-import com.compdfkit.tools.common.utils.CFileUtils;
 import com.compdfkit.tools.common.utils.activitycontracts.CImageResultContracts;
-import com.compdfkit.tools.common.utils.date.CDateUtil;
 import com.compdfkit.tools.common.utils.threadpools.CThreadPoolUtils;
 import com.compdfkit.tools.common.utils.view.sliderbar.CSliderBar;
 import com.compdfkit.tools.common.views.pdfproperties.basic.CBasicPropertiesFragment;
@@ -32,8 +30,6 @@ import com.compdfkit.tools.common.views.pdfproperties.pdfstyle.CAnnotStyle;
 import com.compdfkit.tools.common.views.pdfproperties.pdfstyle.CStyleType;
 import com.compdfkit.tools.common.views.pdfproperties.preview.CStylePreviewView;
 
-import java.io.File;
-
 
 public class CEditImagePropertiesFragment extends CBasicPropertiesFragment implements View.OnClickListener {
     private CStylePreviewView stylePreviewView;

+ 0 - 3
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/forms/pdfformbar/CFormToolbar.java

@@ -14,7 +14,6 @@ import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.widget.FrameLayout;
 
 import androidx.annotation.NonNull;
@@ -26,8 +25,6 @@ import androidx.recyclerview.widget.RecyclerView;
 
 import com.compdfkit.core.annotation.form.CPDFWidget;
 import com.compdfkit.core.undo.CPDFUndoManager;
-import com.compdfkit.core.undo.exception.CPDFRedoFailedException;
-import com.compdfkit.core.undo.exception.CPDFUndoFailedException;
 import com.compdfkit.tools.R;
 import com.compdfkit.tools.common.interfaces.COnFormChangeListener;
 import com.compdfkit.tools.common.utils.CLog;

+ 0 - 4
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/forms/pdfproperties/pdfsign/CustomSignatureWidgetImpl.java

@@ -10,7 +10,6 @@
 package com.compdfkit.tools.forms.pdfproperties.pdfsign;
 
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.text.TextUtils;
 
 import androidx.fragment.app.FragmentActivity;
@@ -25,9 +24,6 @@ import com.compdfkit.tools.common.views.pdfproperties.pdfstyle.CStyleUIParams;
 import com.compdfkit.tools.common.views.pdfproperties.pdfstyle.manager.CStyleManager;
 import com.compdfkit.ui.proxy.form.CPDFSignatureWidgetImpl;
 
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-
 
 public class CustomSignatureWidgetImpl extends CPDFSignatureWidgetImpl {
 

+ 3 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/CSignatureToolBar.java

@@ -71,5 +71,8 @@ public class CSignatureToolBar extends FrameLayout {
         return clVerifySign;
     }
 
+    public void reset(){
+        clAddSignatures.setSelected(false);
+    }
 
 }

+ 207 - 84
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/CertificateDigitalDatas.java

@@ -10,8 +10,11 @@
 package com.compdfkit.tools.signature;
 
 
+import android.content.Context;
 import android.text.TextUtils;
 
+import androidx.annotation.Nullable;
+
 import com.compdfkit.core.annotation.form.CPDFSignatureWidget;
 import com.compdfkit.core.document.CPDFDocument;
 import com.compdfkit.core.document.signature.CPDFCertInfo;
@@ -19,22 +22,43 @@ import com.compdfkit.core.document.signature.CPDFOwnerInfo;
 import com.compdfkit.core.document.signature.CPDFSignature;
 import com.compdfkit.core.document.signature.CPDFSigner;
 import com.compdfkit.core.document.signature.CPDFX509;
+import com.compdfkit.core.utils.TFileUtils;
 import com.compdfkit.tools.common.utils.CLog;
 import com.compdfkit.tools.common.utils.CUriUtil;
 import com.compdfkit.tools.signature.pdfproperties.pdfsign.CDigitalSignStyleData;
 
+import org.jetbrains.annotations.NotNull;
+
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 public class CertificateDigitalDatas {
 
+    /**
+     * Generate a digital signature certificate based on relevant information
+     *
+     * @param ownerInfo Certificate information
+     * @param password
+     * @param saveDir   Local storage save path
+     * @param fileName  Certificate file name
+     * @return Whether a certificate was generated
+     */
     public static boolean generatePKCS12Cert(CPDFOwnerInfo ownerInfo, String password, String saveDir, String fileName) {
         CPDFSignature.CertUsage flag = CPDFSignature.CertUsage.PDFDigSig;
         String pfxPath = new File(saveDir, fileName).getAbsolutePath();
         return CPDFSignature.generatePKCS12Cert(ownerInfo, password, pfxPath, flag, true);
     }
 
+    /**
+     * Get certificate information
+     *
+     * @param certFilePath Certificate local file path
+     * @param password
+     * @return
+     */
+    @Nullable
     public static CPDFCertInfo getCertInfo(String certFilePath, String password) {
         if (CPDFSignature.checkPKCS12Password(certFilePath, password)) {
             CPDFX509 x509 = CPDFSignature.getX509ByPKCS12Cert(certFilePath, password);
@@ -44,6 +68,13 @@ public class CertificateDigitalDatas {
         }
     }
 
+    /**
+     * Get a collection of digital signatures in a pdf document
+     *
+     * @param document
+     * @return
+     */
+    @NotNull
     public static List<CPDFSignature> getDigitalSignList(CPDFDocument document) {
         List<CPDFSignature> list = new ArrayList<>();
         for (int i = 0; i < document.getSignatureCount(); i++) {
@@ -59,108 +90,150 @@ public class CertificateDigitalDatas {
         return list;
     }
 
-    public static boolean signDocument(CPDFDocument document,
-                                       CPDFSignatureWidget signatureWidget,
-                                       CDigitalSignStyleData styleData,
-                                       String certPath,
-                                       String password,
-                                       String savePath
+    public static boolean hasDigitalSignature(CPDFDocument document){
+        return getDigitalSignList(document).size() > 0;
+    }
+
+    /**
+     * Write digital signature into pdf document
+     *
+     * @param document
+     * @param signatureWidget
+     * @param styleData       Signature related information, such as: reason for signing, location, time, etc.
+     * @param certPath        Signed certificate local file path
+     * @param password        certificate password
+     * @param savePath        Document save path
+     * @return
+     */
+    public static boolean writeSignature(CPDFDocument document,
+                                         CPDFSignatureWidget signatureWidget,
+                                         CDigitalSignStyleData styleData,
+                                         String certPath,
+                                         String password,
+                                         String savePath
     ) {
-        return document.writeSignatureToPath(signatureWidget,
-                document.getAbsolutePath(),
-                savePath,
-                certPath,
-                password,
-                styleData.getPosition(),
-                styleData.getReason(),
-                CPDFDocument.PDFDocMdpP.PDFDocMdpPForbidAllModify
-        );
+        if (!TextUtils.isEmpty(document.getAbsolutePath())) {
+            return document.writeSignatureToPath(signatureWidget,
+                    document.getAbsolutePath(),
+                    savePath,
+                    certPath,
+                    password,
+                    styleData.getPosition(),
+                    styleData.getReason(),
+                    CPDFDocument.PDFDocMdpP.PDFDocMdpPForbidAllModify
+            );
+        } else if (document.getUri() != null) {
+            return document.writeSignatureToPath(signatureWidget,
+                    CUriUtil.getUriFd(document.getContext(), document.getUri()),
+                    savePath,
+                    certPath,
+                    password,
+                    styleData.getPosition(),
+                    styleData.getReason(),
+                    CPDFDocument.PDFDocMdpP.PDFDocMdpPForbidAllModify
+            );
+        } else {
+            return false;
+        }
     }
 
-    public static boolean verifySignIsValid(CPDFSignature signature, CPDFDocument document) {
+    /**
+     * Verify that the specified digital signature is valid
+     *
+     * @param signature
+     * @param document
+     * @return
+     */
+    public static boolean verifySignIsValid(CPDFDocument document,CPDFSignature signature ) {
         CPDFSigner[] signers = signature.getSignerArr();
         if (!TextUtils.isEmpty(document.getAbsolutePath())) {
-            return signature.veryfyDocument(document, document.getAbsolutePath());
+            return signature.veryfyByPath(signers[0], document.getAbsolutePath());
         } else {
-            return signature.veryfyByFd(signers[0], CUriUtil.getUriFd(document.getContext(), document.getUri()));
+            return signature.verifyByFd(signers[0], CUriUtil.getUriFd(document.getContext(), document.getUri()));
         }
     }
 
-    public static int verifyDocumentSignStatus(CPDFDocument document) {
-        return 0;
+    /**
+     * Verify whether the document has been modified after the digital signature
+     *
+     * @param document
+     * @param signature
+     * @return
+     */
+    public static boolean verifyDocumentHasChanged(CPDFDocument document, CPDFSignature signature) {
+        return signature.verifyDocument(document);
     }
 
-    public static void readData(CPDFDocument currentDocument) {
-        StringBuilder data = new StringBuilder();
-        data.append("Signature number = " + currentDocument.getSignatureCount() + "\n\n");
-        for (int i = 0; i < currentDocument.getSignatureCount(); i++) {
-            data.append("Signature " + i + ":\n");
-            CPDFSignature signature = currentDocument.getPdfSignature(i);
-            if (signature == null) continue;
-            data.append("reason=" + signature.getReason() + "\ndate=" + signature.getDate() + "\nname=" + signature.getName()
-                    + "\nbounds=" + signature.getBounds().toString() + "\nfilter=" + signature.getFilter() + "\nsubfilter=" + signature.getSubFilter() +
-                    "\nlocate=" + signature.getLocation() + "\npermission=" + signature.getPermissionType() +
-                    "\npageIndex=" + signature.getPageIndex(currentDocument) + " \n");
-
-            CPDFSigner[] signerArr = signature.getSignerArr();
-            if (signerArr != null && signerArr.length > 0) {
-                CPDFSigner signer = signerArr[0];
-                CPDFX509 cert = signer.getCert();
-                CPDFCertInfo info = cert.getCertInfo();
-                data.append("begin date=" + info.getValidDateBegin() + " \nend date=" + info.getValidDateEnd() + " \npublickey=" + info.getPublicKey()
-                        + " \nsubjectname=" + info.getSubject() + " \nversion=" + info.getVersion() + " \nSignature Algrithm=" + info.getSignatureAlgOid()
-                        + " \nissuer=" + info.getIssuer().toString()
-                );
-
-                String[] ocspUrl = info.getOcspURL();
-                if (ocspUrl != null) {
-                    data.append("\nOCSP=");
-                    for (int j = 0; j < ocspUrl.length; j++) {
-                        data.append("\n" + ocspUrl[j]);
-                    }
-                }
-                data.append("\n");
-                String[] crl = info.getExtInfo().getCrlDistribute();
-                if (crl != null) {
-                    data.append("\nCRL:");
-                    for (int j = 0; j < crl.length; j++) {
-                        data.append("\n" + crl[j]);
-                    }
-                }
-                data.append("\n");
-                String[] policies = info.getExtInfo().getCertificatePolicies();
-                if (policies != null) {
-                    data.append("\nPOLICIES:");
-                    for (int j = 0; j < policies.length; j++) {
-                        data.append("\n" + policies[j]);
-                    }
-                }
-                data.append("\n\n");
-
-                int certchain = cert.verifyGetChain(signature, "/storage/emulated/0/certificate.pfx");
-                data.append("verifyGetChain=" + certchain);
-                data.append("\n");
-                CPDFX509[] trust = cert.getChanin();
-                data.append("trust chain:");
-                if (trust == null) {
-                    data.append(0);
-                } else {
-                    data.append(trust.length);
-                }
+    /**
+     * Digital Signature Timestamp Authentication
+     *
+     * @param context
+     * @param signature
+     * @param signer
+     * @return
+     */
+    public static boolean verifyTimeStamp(Context context, CPDFSignature signature, CPDFSigner signer) {
+        return signature.veryfyTimestamp(context, signer);
+    }
 
+    /**
+     * Whether the certificate is trusted
+     *
+     * @param context
+     * @param cert
+     * @param signature
+     * @return
+     */
+    public static boolean verifyGetChain(Context context, CPDFX509 cert, CPDFSignature signature) {
+        return cert.verifyGetChain(context, signature);
+    }
 
-                String documentPath = currentDocument.getAbsolutePath();
-                if (!TextUtils.isEmpty(documentPath)) {
-                    data.append("\n\n veryfy=" + signature.veryfyByPath(signer, documentPath));
-                    data.append("\n veryfy document=" + signature.veryfyDocument(currentDocument, documentPath));
-                }
-                data.append("\n has been modified:" + signature.haveDiffInfo());
 
+    public static SignatureStatus verifyDocumentSignStatus(CPDFDocument document) {
+        List<CPDFSignature> signatures = getDigitalSignList(document);
+        if (signatures != null && signatures.size() > 0) {
+            boolean hasInValid = false;
+            for (CPDFSignature signature : signatures) {
+                boolean result = verifySignIsValid(document, signature);
+                if (!result) {
+                    // Invalid digital signature
+                    hasInValid = true;
+                }
             }
-            data.append("\n===============================\n");
+            // Invalid signature in digital signature collection
+            if (hasInValid) {
+                return SignatureStatus.FAILURES;
+            }
+            // All the signatures in the digital signature set are valid,
+            // and it is judged whether there is an expired certificate
+            boolean hasIsExpiredSignature = false;
+            for (CPDFSignature signature : signatures) {
+                CPDFSigner[] signers = signature.getSignerArr();
+                CPDFSigner signers1 = signers[0];
+                if (signers1.getCert().isExpired()) {
+                    hasIsExpiredSignature = true;
+                }
+            }
+            return hasIsExpiredSignature ? SignatureStatus.WRONG : SignatureStatus.VALID;
+        } else {
+            return SignatureStatus.FAILURES;
         }
     }
 
+    public static SignatureStatus verifySignatureStatus(CPDFDocument document, CPDFSignature signature){
+        boolean isValid = verifySignIsValid( document, signature);
+        if (isValid) {
+            boolean isExpired = false;
+            CPDFSigner[] signers = signature.getSignerArr();
+            CPDFSigner signers1 = signers[0];
+            if (signers1.getCert().isExpired()) {
+                isExpired = true;
+            }
+            return isExpired ? SignatureStatus.WRONG : SignatureStatus.VALID;
+        }else {
+            return SignatureStatus.FAILURES;
+        }
+    }
 
     public static boolean removeDigitalSign(CPDFDocument document, CPDFSignature signature) {
         try {
@@ -172,4 +245,54 @@ public class CertificateDigitalDatas {
             return false;
         }
     }
+
+    public static List<CPDFX509> getCertDetails(Context context, CPDFSignature signature){
+        CPDFSigner[] signers = signature.getSignerArr();
+        List<CPDFX509> list = new ArrayList<>();
+        if (signers != null && signers.length > 0){
+            CPDFSigner signer = signers[0];
+            CPDFX509 cert = signer.getCert();
+            list.add(cert);
+            loopVerifyGetChain(context,list, signature, cert);
+        }
+        Collections.reverse(list);
+        return list;
+    }
+
+    private static void loopVerifyGetChain(Context context,List<CPDFX509> list, CPDFSignature signature, CPDFX509 cert){
+        cert.verifyGetChain(context, signature);
+        CPDFX509[] cpdfx509s = cert.getChanin();
+        if (cpdfx509s != null && cpdfx509s.length > 0) {
+            CPDFX509 a = cpdfx509s[0];
+            list.add(a);
+            loopVerifyGetChain(context, list, signature, a);
+        }
+    }
+
+
+    public static String getOwnerContent(CPDFOwnerInfo ownerInfo){
+        StringBuilder builder = new StringBuilder();
+        List<String> infos = new ArrayList<>();
+        if (!TextUtils.isEmpty(ownerInfo.getCountry())){
+            infos.add("C="+ownerInfo.getCountry());
+        }
+        if (!TextUtils.isEmpty(ownerInfo.getOrgnize())){
+            infos.add("O="+ownerInfo.getOrgnize());
+        }
+        if (!TextUtils.isEmpty(ownerInfo.getOrgnizeUnit())){
+            infos.add("OU="+ownerInfo.getOrgnizeUnit());
+        }
+        if (!TextUtils.isEmpty(ownerInfo.getCommonName())){
+            infos.add("CN="+ownerInfo.getCommonName());
+        }
+        for (int i = 0; i < infos.size(); i++) {
+            String item = infos.get(i);
+            builder.append(item);
+            if (i != infos.size() -1){
+                builder.append(",");
+            }
+        }
+        return builder.toString();
+    }
+
 }

+ 20 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/SignatureStatus.java

@@ -0,0 +1,20 @@
+/**
+ * Copyright © 2014-2023 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
+package com.compdfkit.tools.signature;
+
+
+public enum SignatureStatus {
+
+    VALID,
+
+    FAILURES,
+
+    WRONG
+}

+ 64 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/bean/CPDFCertAttrDataItem.java

@@ -0,0 +1,64 @@
+/**
+ * Copyright © 2014-2023 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
+package com.compdfkit.tools.signature.bean;
+
+
+public class CPDFCertAttrDataItem {
+
+    public CPDFCertAttrDataItem(String headTitle){
+        this.headTitle = headTitle;
+        this.isHead = true;
+    }
+
+    public CPDFCertAttrDataItem(String title, String value){
+        this.title = title;
+        this.value = value;
+    }
+
+    private boolean isHead;
+
+    private String headTitle;
+
+    private String title;
+
+    private String value;
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public boolean isHead() {
+        return isHead;
+    }
+
+    public void setHead(boolean head) {
+        isHead = head;
+    }
+
+    public String getHeadTitle() {
+        return headTitle;
+    }
+
+    public void setHeadTitle(String headTitle) {
+        this.headTitle = headTitle;
+    }
+}

+ 93 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/bean/CPDFOwnerItemData.java

@@ -0,0 +1,93 @@
+/**
+ * Copyright © 2014-2023 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
+package com.compdfkit.tools.signature.bean;
+
+
+import android.text.TextUtils;
+
+import com.compdfkit.core.document.signature.CPDFOwnerInfo;
+import com.compdfkit.core.document.signature.CPDFX509;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CPDFOwnerItemData {
+
+    public CPDFOwnerItemData() {
+
+    }
+
+    public CPDFOwnerItemData(CPDFX509 cpdfx509){
+        this.cpdfx509 = cpdfx509;
+        StringBuilder builder = new StringBuilder();
+        CPDFOwnerInfo ownerInfo = cpdfx509.getCertInfo().getSubject();
+        List<String> infos = new ArrayList<>();
+        if (!TextUtils.isEmpty(ownerInfo.getCountry())){
+            infos.add("C="+ownerInfo.getCountry());
+        }
+        if (!TextUtils.isEmpty(ownerInfo.getOrgnize())){
+            infos.add("O="+ownerInfo.getOrgnize());
+        }
+        if (!TextUtils.isEmpty(ownerInfo.getOrgnizeUnit())){
+            infos.add("OU="+ownerInfo.getOrgnizeUnit());
+        }
+        if (!TextUtils.isEmpty(ownerInfo.getCommonName())){
+            infos.add("CN="+ownerInfo.getCommonName());
+        }
+        for (int i = 0; i < infos.size(); i++) {
+            String item = infos.get(i);
+            builder.append(item);
+            if (i != infos.size() -1){
+                builder.append(",");
+            }
+        }
+        this.content = builder.toString();
+    }
+
+    private CPDFX509 cpdfx509;
+
+    private String content;
+
+    private boolean isExpanded = true;
+
+    private boolean hasParent;
+
+    public CPDFX509 getCpdfx509() {
+        return cpdfx509;
+    }
+
+    public void setCpdfx509(CPDFX509 cpdfx509) {
+        this.cpdfx509 = cpdfx509;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public void setExpanded(boolean expanded) {
+        isExpanded = expanded;
+    }
+
+    public boolean isExpanded() {
+        return isExpanded;
+    }
+
+    public void setHasParent(boolean hasParent) {
+        this.hasParent = hasParent;
+    }
+
+    public boolean isHasParent() {
+        return hasParent;
+    }
+}

+ 8 - 7
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/bean/CPDFSignatureItemData.java

@@ -2,19 +2,20 @@ package com.compdfkit.tools.signature.bean;
 
 
 import com.compdfkit.core.document.signature.CPDFSignature;
+import com.compdfkit.tools.signature.SignatureStatus;
 
 public class CPDFSignatureItemData {
 
     public CPDFSignatureItemData(){}
 
-    public CPDFSignatureItemData(CPDFSignature signature, boolean isValid){
+    public CPDFSignatureItemData(CPDFSignature signature, SignatureStatus signatureStatus){
         this.signature = signature;
-        this.isValid = isValid;
+        this.signatureStatus = signatureStatus;
     }
 
     private CPDFSignature signature;
 
-    private boolean isValid;
+    private SignatureStatus signatureStatus;
 
     public CPDFSignature getSignature() {
         return signature;
@@ -24,11 +25,11 @@ public class CPDFSignatureItemData {
         this.signature = signature;
     }
 
-    public boolean isValid() {
-        return isValid;
+    public SignatureStatus getSignatureStatus() {
+        return signatureStatus;
     }
 
-    public void setValid(boolean valid) {
-        isValid = valid;
+    public void setSignatureStatus(SignatureStatus signatureStatus) {
+        this.signatureStatus = signatureStatus;
     }
 }

+ 27 - 22
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/importcert/create/CImportCertificateDigitalDialog.java

@@ -35,6 +35,7 @@ import androidx.constraintlayout.widget.ConstraintLayout;
 
 import com.compdfkit.core.document.signature.CPDFSignature;
 import com.compdfkit.tools.R;
+import com.compdfkit.tools.common.basic.fragment.CBasicBottomSheetDialogFragment;
 import com.compdfkit.tools.common.utils.CFileUtils;
 import com.compdfkit.tools.common.utils.CUriUtil;
 import com.compdfkit.tools.common.utils.dialog.CDialogFragmentUtil;
@@ -45,7 +46,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
 
 import java.io.File;
 
-public class CImportCertificateDigitalDialog extends BottomSheetDialogFragment implements View.OnClickListener {
+public class CImportCertificateDigitalDialog extends CBasicBottomSheetDialogFragment implements View.OnClickListener {
 
     public static final String EXTRA_CERTIFICATE_DIGITAL_URI = "extra_certificate_digital_uri";
 
@@ -90,23 +91,12 @@ public class CImportCertificateDigitalDialog extends BottomSheetDialogFragment i
     }
 
     @Override
-    public void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setStyle(STYLE_NORMAL, R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle_TopCorners);
+    protected int layoutId() {
+        return R.layout.tools_sign_import_certificate_digital_id_fragment;
     }
 
     @Override
-    public void onStart() {
-        super.onStart();
-        BottomSheetBehavior<View> behavior = BottomSheetBehavior.from((View) getView().getParent());
-        CDialogFragmentUtil.setBottomSheetDialogFragmentFullScreen(getDialog(), behavior);
-        behavior.setDraggable(false);
-    }
-
-    @Nullable
-    @Override
-    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-        View view = inflater.inflate(R.layout.tools_sign_import_certificate_digital_id_fragment, container, false);
+    protected void onCreateView(View view) {
         tvTitle = view.findViewById(R.id.tv_tool_bar_title);
         ivClose = view.findViewById(R.id.iv_tool_bar_close);
         clCertificate = view.findViewById(R.id.cl_certificate);
@@ -120,18 +110,32 @@ public class CImportCertificateDigitalDialog extends BottomSheetDialogFragment i
         btnOk.setOnClickListener(this);
         clCertificate.setOnClickListener(this);
         etPassword.setOnEditorActionListener((v, actionId, event) -> {
-            if (actionId == EditorInfo.IME_ACTION_DONE){
+            if (actionId == EditorInfo.IME_ACTION_DONE) {
                 verifyCertificate();
                 return true;
             }
             return false;
         });
-        return view;
+    }
+
+
+    @Override
+    protected boolean fullScreen() {
+        return true;
     }
 
     @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
+    protected int getStyle() {
+        return R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle_TopCorners;
+    }
+
+    @Override
+    protected boolean draggable() {
+        return false;
+    }
+
+    @Override
+    protected void onViewCreate() {
         Uri uri = getArguments().getParcelable(EXTRA_CERTIFICATE_DIGITAL_URI);
         if (uri != null) {
             setCertificateInfo(uri);
@@ -159,6 +163,7 @@ public class CImportCertificateDigitalDialog extends BottomSheetDialogFragment i
         });
     }
 
+
     @Override
     public void onClick(View v) {
         if (v.getId() == R.id.iv_tool_bar_close) {
@@ -181,15 +186,15 @@ public class CImportCertificateDigitalDialog extends BottomSheetDialogFragment i
         CViewUtils.showKeyboard(etPassword);
     }
 
-    private void verifyCertificate(){
-        if (TextUtils.isEmpty(etPassword.getText())){
+    private void verifyCertificate() {
+        if (TextUtils.isEmpty(etPassword.getText())) {
             tvPasswordError.setVisibility(View.VISIBLE);
             return;
         }
         String password = etPassword.getText().toString();
         String dir = new File(getContext().getCacheDir(), CFileUtils.CACHE_FOLDER + File.separator + "certFile").getAbsolutePath();
         String certPath = CFileUtils.copyFileToInternalDirectory(getContext(), certificateUri, dir, CUriUtil.getUriFileName(getContext(), certificateUri));
-        if (!CPDFSignature.checkPKCS12Password(certPath, password)){
+        if (!CPDFSignature.checkPKCS12Password(certPath, password)) {
             tvPasswordError.setVisibility(View.VISIBLE);
             return;
         }

+ 1 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/importcert/create/CPDFSelectDigitalSignatureDialog.java

@@ -131,7 +131,7 @@ public class CPDFSelectDigitalSignatureDialog extends DialogFragment implements
         } else if (v.getId() == R.id.btn_confirm) {
             if (!CPermissionUtil.hasStoragePermissions(getContext())){
                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
-                    CPermissionUtil.openAppSettings(getContext());
+                    CPermissionUtil.openManageAllFileAppSettings(getContext());
                 }else {
                     requestStorageLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE);
                 }

+ 0 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/importcert/create/CountryReginSpinnerAdapter.java

@@ -19,7 +19,6 @@ import android.widget.BaseAdapter;
 import androidx.annotation.NonNull;
 import androidx.appcompat.widget.AppCompatTextView;
 
-import com.compdfkit.core.annotation.CPDFTextAttribute;
 import com.compdfkit.tools.R;
 
 import java.util.List;

+ 19 - 16
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/importcert/create/CreateCertificateDigitalDialog.java

@@ -37,6 +37,7 @@ import androidx.appcompat.widget.AppCompatTextView;
 
 import com.compdfkit.core.document.signature.CPDFOwnerInfo;
 import com.compdfkit.tools.R;
+import com.compdfkit.tools.common.basic.fragment.CBasicBottomSheetDialogFragment;
 import com.compdfkit.tools.common.utils.CFileUtils;
 import com.compdfkit.tools.common.utils.dialog.CDialogFragmentUtil;
 import com.compdfkit.tools.common.utils.threadpools.CThreadPoolUtils;
@@ -53,7 +54,7 @@ import java.util.Locale;
 import java.util.UUID;
 
 
-public class CreateCertificateDigitalDialog extends BottomSheetDialogFragment implements View.OnClickListener {
+public class CreateCertificateDigitalDialog extends CBasicBottomSheetDialogFragment implements View.OnClickListener {
 
     private AppCompatTextView tvTitle;
 
@@ -118,9 +119,8 @@ public class CreateCertificateDigitalDialog extends BottomSheetDialogFragment im
     }
 
     @Override
-    public void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setStyle(STYLE_NORMAL, R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle_TopCorners);
+    protected int getStyle() {
+        return R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle_TopCorners;
     }
 
     @NonNull
@@ -147,17 +147,22 @@ public class CreateCertificateDigitalDialog extends BottomSheetDialogFragment im
     }
 
     @Override
-    public void onStart() {
-        super.onStart();
-        BottomSheetBehavior<View> behavior = BottomSheetBehavior.from((View) getView().getParent());
-        CDialogFragmentUtil.setBottomSheetDialogFragmentFullScreen(getDialog(), behavior);
-        behavior.setDraggable(false);
+    protected boolean draggable() {
+        return false;
     }
 
-    @Nullable
     @Override
-    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-        View view = inflater.inflate(R.layout.tools_sign_create_cert_digital_id_fragment, container, false);
+    protected boolean fullScreen() {
+        return true;
+    }
+
+    @Override
+    protected int layoutId() {
+        return R.layout.tools_sign_create_cert_digital_id_fragment;
+    }
+
+    @Override
+    protected void onCreateView(View view) {
         tvTitle = view.findViewById(R.id.tv_tool_bar_title);
         ivClose = view.findViewById(R.id.iv_tool_bar_close);
         etName = view.findViewById(R.id.et_name);
@@ -179,14 +184,12 @@ public class CreateCertificateDigitalDialog extends BottomSheetDialogFragment im
         tvSaveAddress.setOnClickListener(this);
         btnConfirmCreate.setOnClickListener(this);
         ivClose.setOnClickListener(this);
-        return view;
     }
 
     @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
+    protected void onViewCreate() {
         String uuid = UUID.randomUUID().toString();
-        String fileName = "new_cert_"+  uuid.substring(uuid.length()-4, uuid.length())+".p12";
+        fileName = "new_cert_"+  uuid.substring(uuid.length()-4, uuid.length())+".p12";
         tvTitle.setText(R.string.tools_create_a_self_signed_digital_id);
         initCountryReginData();
         etName.addTextChangedListener((s, start, before, count) -> {

+ 129 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/CertAttrDatas.java

@@ -0,0 +1,129 @@
+/**
+ * Copyright © 2014-2023 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
+package com.compdfkit.tools.signature.info;
+
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import com.compdfkit.core.document.signature.CPDFAuinfoac;
+import com.compdfkit.core.document.signature.CPDFCertInfo;
+import com.compdfkit.core.document.signature.CPDFExtInfo;
+import com.compdfkit.core.document.signature.CPDFOwnerInfo;
+import com.compdfkit.core.document.signature.CPDFX509;
+import com.compdfkit.tools.R;
+import com.compdfkit.tools.common.utils.date.CDateUtil;
+import com.compdfkit.tools.signature.bean.CPDFCertAttrDataItem;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CertAttrDatas {
+
+    public static List<CPDFCertAttrDataItem> getAbstractInfo(Context context, CPDFX509 cpdfx509){
+        List<CPDFCertAttrDataItem> list = new ArrayList<>();
+        CPDFCertInfo certInfo = cpdfx509.getCertInfo();
+        CPDFExtInfo extInfo = certInfo.getExtInfo();
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_subject), getOwnerContent(certInfo.getSubject())));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_issuer), getOwnerContent(certInfo.getIssuer())));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_valid_start_date), CDateUtil.formatPDFUTCDate(certInfo.getValidDateBegin())));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_valid_until_date), CDateUtil.formatPDFUTCDate(certInfo.getValidDateEnd())));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_expected_usage), ""));
+        return list;
+    }
+
+
+    public static List<CPDFCertAttrDataItem> getCertAttrDetailInfoList(Context context, CPDFX509 cpdfx509){
+        List<CPDFCertAttrDataItem> list = new ArrayList<>();
+        CPDFCertInfo certInfo = cpdfx509.getCertInfo();
+        CPDFExtInfo extInfo = certInfo.getExtInfo();
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_version), certInfo.getVersion()));
+        CPDFCertInfo.CPDFAlgorithmType algorithmType = certInfo.getAlgorithmType(certInfo.getSignatureAlgOid());
+        String signatureAlgorithm = algorithmType.name().replace("PDFSignatureAlgorithmType","");
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_signature_algorithm), signatureAlgorithm + "(" +  certInfo.getSignatureAlgOid() +")"));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_subject), getOwnerContent(certInfo.getSubject())));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_issuer), getOwnerContent(certInfo.getIssuer())));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_valid_start_date), CDateUtil.formatPDFUTCDate(certInfo.getValidDateBegin())));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_valid_until_date), CDateUtil.formatPDFUTCDate(certInfo.getValidDateEnd())));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_certificate_policy), getCertStringArrayInfo(extInfo.getCertificatePolicies())));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_crl_distribution_point), getCertStringArrayInfo(extInfo.getCrlDistribute())));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_auth_info_access), getAuthInfoAccessContent(extInfo.getAuthorizedInforAccess())));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_issuing_auth_key_identifier), extInfo.getAuthKeyIdentifier()));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_subject_key_identifier), extInfo.getSubjectKeyIdentifier()));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_basic_limit), ""));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_key_usage), extInfo.getKeyUsage()));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_public_key), certInfo.getPublicKey()));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_x_509_data), certInfo.getX509Data()));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_sha1_digest), certInfo.getSha1Digest()));
+        list.add(new CPDFCertAttrDataItem(context.getString(R.string.tools_md5_digest), certInfo.getMd5Digest()));
+        return list;
+    }
+
+    private static String getAuthInfoAccessContent(CPDFAuinfoac[] cpdfAuinfoacs){
+        if (cpdfAuinfoacs != null && cpdfAuinfoacs.length > 0) {
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < cpdfAuinfoacs.length; i++) {
+                CPDFAuinfoac item = cpdfAuinfoacs[i];
+                if (item != null){
+                    builder.append("methodType:").append(item.getMethod_type()).append("\n");
+                    builder.append("nid:").append(item.getNid()).append("\n");
+                    builder.append("URL:").append(item.getUrl());
+                }
+                if (i != cpdfAuinfoacs.length -1){
+                    builder.append("\n\n");
+                }
+            }
+            return builder.toString();
+        }
+        return "";
+    }
+
+    private static String getCertStringArrayInfo(String[] array){
+        if (array != null && array.length > 0){
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < array.length; i++) {
+                String policy = array[i];
+                builder.append(policy);
+                if (i != array.length -1){
+                    builder.append("\n");
+                }
+            }
+            return builder.toString();
+        }
+        return "";
+    }
+
+
+    private static String getOwnerContent(CPDFOwnerInfo ownerInfo){
+        StringBuilder builder = new StringBuilder();
+        List<String> infos = new ArrayList<>();
+        if (!TextUtils.isEmpty(ownerInfo.getCountry())){
+            infos.add("C="+ownerInfo.getCountry());
+        }
+        if (!TextUtils.isEmpty(ownerInfo.getOrgnize())){
+            infos.add("O="+ownerInfo.getOrgnize());
+        }
+        if (!TextUtils.isEmpty(ownerInfo.getOrgnizeUnit())){
+            infos.add("OU="+ownerInfo.getOrgnizeUnit());
+        }
+        if (!TextUtils.isEmpty(ownerInfo.getCommonName())){
+            infos.add("CN="+ownerInfo.getCommonName());
+        }
+        for (int i = 0; i < infos.size(); i++) {
+            String item = infos.get(i);
+            builder.append(item);
+            if (i != infos.size() -1){
+                builder.append("\n");
+            }
+        }
+        return builder.toString();
+    }
+
+}

+ 57 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/CertAttrListAdapter.java

@@ -0,0 +1,57 @@
+/**
+ * Copyright © 2014-2023 PDF Technologies, Inc. All Rights Reserved.
+ * <p>
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
+package com.compdfkit.tools.signature.info;
+
+import android.content.Context;
+import android.view.ViewGroup;
+
+import com.compdfkit.tools.R;
+import com.compdfkit.tools.common.utils.adapter.CBaseQuickAdapter;
+import com.compdfkit.tools.common.utils.adapter.CBaseQuickViewHolder;
+import com.compdfkit.tools.signature.bean.CPDFCertAttrDataItem;
+
+import java.util.EventListener;
+
+
+public class CertAttrListAdapter extends CBaseQuickAdapter<CPDFCertAttrDataItem, CBaseQuickViewHolder> {
+
+    public static final int ITEM_HEAD = 0;
+
+    public static final int ITEM_CONTENT = 1;
+
+    @Override
+    protected CBaseQuickViewHolder onCreateViewHolder(Context context, ViewGroup parent, int viewType) {
+        if (viewType == ITEM_HEAD){
+            return new CBaseQuickViewHolder(R.layout.tools_sign_certificate_attributes_list_head_item, parent);
+        }else {
+            return new CBaseQuickViewHolder(R.layout.tools_sign_certificate_attributes_list_item, parent);
+        }
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        if (list.get(position).isHead()) {
+            return ITEM_HEAD;
+        } else {
+            return ITEM_CONTENT;
+        }
+    }
+
+    @Override
+    protected void onBindViewHolder(CBaseQuickViewHolder holder, int position, CPDFCertAttrDataItem item) {
+        if (item.isHead()) {
+            holder.setText(R.id.tv_head, item.getHeadTitle());
+        }else {
+            holder.setText(R.id.tv_attr_title, item.getTitle() + ":");
+            holder.setText(R.id.tv_attr_value, item.getValue());
+        }
+
+    }
+}

+ 71 - 25
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/CertDetailsDialog.java

@@ -19,63 +19,109 @@ import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.appcompat.widget.AppCompatImageView;
 import androidx.appcompat.widget.AppCompatTextView;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
 
+import com.compdfkit.core.document.signature.CPDFCertInfo;
+import com.compdfkit.core.document.signature.CPDFSignature;
+import com.compdfkit.core.document.signature.CPDFSigner;
+import com.compdfkit.core.document.signature.CPDFX509;
 import com.compdfkit.tools.R;
+import com.compdfkit.tools.common.basic.fragment.CBasicBottomSheetDialogFragment;
+import com.compdfkit.tools.common.utils.CLog;
 import com.compdfkit.tools.common.utils.dialog.CDialogFragmentUtil;
+import com.compdfkit.tools.common.utils.viewutils.CViewUtils;
+import com.compdfkit.tools.common.views.CToolBar;
+import com.compdfkit.tools.signature.CertificateDigitalDatas;
+import com.compdfkit.tools.signature.bean.CPDFOwnerItemData;
 import com.google.android.material.bottomsheet.BottomSheetBehavior;
 import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
 
-public class CertDetailsDialog extends BottomSheetDialogFragment implements View.OnClickListener {
+import java.util.ArrayList;
+import java.util.List;
 
-    private AppCompatTextView tvTitle;
+public class CertDetailsDialog extends CBasicBottomSheetDialogFragment {
 
-    private AppCompatImageView ivClose;
+    private CToolBar toolBar;
 
+    private RecyclerView recyclerView;
 
-    public static CertDetailsDialog newInstance() {
+    private CPDFSignature signature;
+
+    private CertDetailsListAdapter detailsListAdapter;
+
+    public static CertDetailsDialog newInstance(CPDFSignature signature) {
         Bundle args = new Bundle();
         CertDetailsDialog fragment = new CertDetailsDialog();
+        fragment.setSignature(signature);
         fragment.setArguments(args);
         return fragment;
     }
 
-    @Override
-    public void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setStyle(STYLE_NORMAL, R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle);
+    public void setSignature(CPDFSignature signature) {
+        this.signature = signature;
     }
 
+
     @Override
-    public void onStart() {
-        super.onStart();
-        BottomSheetBehavior<View> behavior = BottomSheetBehavior.from((View) getView().getParent());
-        CDialogFragmentUtil.setBottomSheetDialogFragmentFullScreen(getDialog(), behavior);
+    protected int getStyle() {
+        return  R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle;
     }
 
-    @Nullable
     @Override
-    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-        View view = inflater.inflate(R.layout.tools_sign_certificate_digital_sign_info_fragment, container, false);
-        tvTitle = view.findViewById(R.id.tv_tool_bar_title);
-        ivClose = view.findViewById(R.id.iv_tool_bar_close);
+    protected boolean fullScreen() {
+        return true;
+    }
 
-        ivClose.setOnClickListener(this);
+    @Override
+    protected float dimAmount() {
+        return CViewUtils.isLandScape(getContext()) ? 0.2F : 0F;
+    }
 
-        return view;
+    @Override
+    protected boolean draggable() {
+        return false;
     }
 
     @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
-        tvTitle.setText(R.string.tools_create_a_self_signed_digital_id);
+    protected int layoutId() {
+        return R.layout.tools_sign_certificate_details_dialog;
     }
 
     @Override
-    public void onClick(View v) {
-        if (v.getId() == R.id.iv_tool_bar_close) {
+    protected void onCreateView(View view) {
+        toolBar = view.findViewById(R.id.tool_bar);
+        recyclerView = view.findViewById(R.id.recycler_view);
+        toolBar.setBackBtnClickListener(v -> {
             dismiss();
-        }
+        });
     }
 
+    @Override
+    protected void onViewCreate() {
+        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        detailsListAdapter = new CertDetailsListAdapter();
+        recyclerView.setAdapter(detailsListAdapter);
+        CertificateDigitalDatas.getCertDetails(getContext(), signature);
+        detailsListAdapter.setOnItemClickListener((adapter, view1, position) -> {
+            CPDFOwnerItemData item = detailsListAdapter.list.get(position);
+            CertDigitalSignAttributesDialog dialog = CertDigitalSignAttributesDialog.newInstance(item.getCpdfx509());
+            dialog.show(getChildFragmentManager(), "certAttrDialog");
+        });
+        initData();
+    }
 
+    private void initData(){
+        List<CPDFX509> list = CertificateDigitalDatas.getCertDetails(getContext(), signature);
+        List<CPDFOwnerItemData> dataList = new ArrayList<>();
+        for (int i = 0; i < list.size(); i++) {
+            CPDFX509 cpdfx509 = list.get(i);
+            CPDFOwnerItemData data = new CPDFOwnerItemData(cpdfx509);
+            if (i != list.size() -1){
+                data.setHasParent(true);
+            }
+            dataList.add(data);
+        }
+        detailsListAdapter.setList(dataList);
+    }
 }

+ 102 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/CertDetailsListAdapter.java

@@ -0,0 +1,102 @@
+/**
+ * Copyright © 2014-2023 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
+package com.compdfkit.tools.signature.info;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.widget.AppCompatTextView;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.compdfkit.tools.R;
+import com.compdfkit.tools.common.utils.adapter.CBaseQuickAdapter;
+import com.compdfkit.tools.common.utils.adapter.CBaseQuickViewHolder;
+import com.compdfkit.tools.common.utils.viewutils.CDimensUtils;
+import com.compdfkit.tools.signature.bean.CPDFOwnerItemData;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class CertDetailsListAdapter extends CBaseQuickAdapter<CPDFOwnerItemData, CBaseQuickViewHolder> {
+
+    private static final String REFRESH_ARROW = "refresh_arrow";
+
+    private List<CPDFOwnerItemData> backList = new ArrayList<>();
+
+    @Override
+    public void setList(List<CPDFOwnerItemData> list) {
+        super.setList(list);
+        backList.addAll(list);
+    }
+
+    @Override
+    protected CBaseQuickViewHolder onCreateViewHolder(Context context, ViewGroup parent, int viewType) {
+        return new CBaseQuickViewHolder(R.layout.tools_sign_certificate_details_list_item, parent);
+    }
+
+    @Override
+    protected void onBindViewHolder(CBaseQuickViewHolder holder, int position, CPDFOwnerItemData item) {
+        holder.setText(R.id.tv_item_title, item.getContent());
+        ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) holder.getView(R.id.iv_item_arrow).getLayoutParams();
+        layoutParams.setMarginStart(getLevelMargin(holder.itemView.getContext(), position +1));
+        holder.setBackgroundColor(R.id.cl_root, ContextCompat.getColor(holder.itemView.getContext(), position == 0 ? R.color.tools_reader_setting_head_bg_color : R.color.tools_color_background));
+        AppCompatTextView title = holder.getView(R.id.tv_item_title);
+        title.setTypeface(position == 0 ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT);
+        holder.setImageResource(R.id.iv_item_arrow, item.isExpanded() ? R.drawable.tools_ic_arrow_down : R.drawable.tools_ic_right);
+        View view = holder.getView(R.id.iv_item_arrow);
+        view.setVisibility(item.isHasParent() ? View.VISIBLE : View.INVISIBLE);
+        holder.setOnClickListener(R.id.iv_item_arrow, v -> {
+            if (item.isExpanded()) {
+                collapseItem(position, item);
+            }else {
+                expandItem(position, item);
+            }
+        });
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+        super.onBindViewHolder(holder, position);
+        CPDFOwnerItemData item = list.get(position);
+        ((CBaseQuickViewHolder) holder)
+                .setImageResource(R.id.iv_item_arrow, item.isExpanded() ? R.drawable.tools_ic_arrow_down : R.drawable.tools_ic_right);
+    }
+
+    private int getLevelMargin(Context context, int position) {
+        return CDimensUtils.dp2px(context, (position - 1) * 15);
+    }
+
+    private void expandItem(int positionStart, CPDFOwnerItemData item) {
+        item.setExpanded(true);
+        List<CPDFOwnerItemData> tempList = new ArrayList<>(backList.subList(positionStart +1, backList.size()));
+        list.addAll(positionStart + 1, tempList);
+        // Notify the adapter that the arrow status of the clicked item has changed
+        notifyItemChanged(positionStart, REFRESH_ARROW);
+        // Notify the adapter that data has been inserted
+        notifyItemRangeInserted(positionStart + 1, tempList.size());
+    }
+
+
+    private void collapseItem(int positionStart, CPDFOwnerItemData item) {
+        item.setExpanded(false);
+        int removeCount = list.size() - positionStart -1;
+        for (int i = list.size() -1; i > positionStart; i--) {
+            list.remove(i);
+        }
+        notifyItemChanged(positionStart, REFRESH_ARROW);
+        notifyItemRangeRemoved(positionStart + 1, removeCount);
+    }
+}

+ 56 - 35
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/CertDigitalSignAttributesDialog.java

@@ -17,74 +17,95 @@ import android.view.ViewGroup;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.appcompat.widget.AppCompatTextView;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
 
+import com.compdfkit.core.document.signature.CPDFCertInfo;
+import com.compdfkit.core.document.signature.CPDFX509;
 import com.compdfkit.tools.R;
+import com.compdfkit.tools.common.basic.fragment.CBasicBottomSheetDialogFragment;
 import com.compdfkit.tools.common.utils.dialog.CDialogFragmentUtil;
+import com.compdfkit.tools.common.utils.viewutils.CViewUtils;
 import com.compdfkit.tools.common.views.CToolBar;
+import com.compdfkit.tools.signature.bean.CPDFCertAttrDataItem;
 import com.google.android.material.bottomsheet.BottomSheetBehavior;
 import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
 
-public class CertDigitalSignAttributesDialog extends BottomSheetDialogFragment {
+import java.util.ArrayList;
+import java.util.List;
 
-    private CToolBar toolBar;
-
-    private AppCompatTextView tvVersion;
-
-    private AppCompatTextView tvSignOrithm;
-
-    private AppCompatTextView tvThematic;
-
-    private AppCompatTextView tvProductKey;
+public class CertDigitalSignAttributesDialog extends CBasicBottomSheetDialogFragment {
 
-    private AppCompatTextView tvValidityPeriod;
+    private CToolBar toolBar;
 
-    private AppCompatTextView tvCertPolicy;
+    private RecyclerView recyclerView;
 
-    private AppCompatTextView tvCrlPoint;
+    private CPDFX509 cpdfx509;
 
+    private CertAttrListAdapter attrListAdapter;
 
-    public static CertDigitalSignAttributesDialog newInstance() {
+    public static CertDigitalSignAttributesDialog newInstance(CPDFX509 cpdfx509) {
         Bundle args = new Bundle();
         CertDigitalSignAttributesDialog fragment = new CertDigitalSignAttributesDialog();
+        fragment.setCpdfx509(cpdfx509);
         fragment.setArguments(args);
         return fragment;
     }
 
+    public void setCpdfx509(CPDFX509 cpdfx509) {
+        this.cpdfx509 = cpdfx509;
+    }
+
+    @Override
+    protected int getStyle() {
+        return R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle;
+    }
+
+    @Override
+    protected boolean fullScreen() {
+        return true;
+    }
+
     @Override
-    public void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setStyle(STYLE_NORMAL, R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle);
+    protected float dimAmount() {
+        return CViewUtils.isLandScape(getContext()) ? 0.2F : 0F;
     }
 
     @Override
-    public void onStart() {
-        super.onStart();
-        BottomSheetBehavior<View> behavior = BottomSheetBehavior.from((View) getView().getParent());
-        CDialogFragmentUtil.setBottomSheetDialogFragmentFullScreen(getDialog(), behavior);
+    protected boolean draggable() {
+        return false;
     }
 
-    @Nullable
     @Override
-    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-        View view = inflater.inflate(R.layout.tools_sign_certificate_attributes_fragment, container, false);
+    protected int layoutId() {
+        return R.layout.tools_sign_certificate_attributes_fragment;
+    }
+
+    @Override
+    protected void onCreateView(View view) {
         toolBar = view.findViewById(R.id.tool_bar);
-        tvVersion = view.findViewById(R.id.tv_version_value);
-        tvSignOrithm = view.findViewById(R.id.tv_sign_orithm_value);
-        tvThematic = view.findViewById(R.id.tv_thematic_value);
-        tvProductKey = view.findViewById(R.id.tv_product_key_value);
-        tvValidityPeriod = view.findViewById(R.id.tv_validity_period_value);
-        tvCertPolicy = view.findViewById(R.id.tv_cert_policy_value);
-        tvCrlPoint = view.findViewById(R.id.tv_crl_distri_value);
+        recyclerView = view.findViewById(R.id.recycler_view);
         toolBar.setBackBtnClickListener(v -> {
             dismiss();
         });
-        return view;
     }
 
     @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
+    protected void onViewCreate() {
+        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        attrListAdapter = new CertAttrListAdapter();
+        recyclerView.setAdapter(attrListAdapter);
+        initData();
     }
 
+    private void initData() {
+        if (cpdfx509 != null) {
+            List<CPDFCertAttrDataItem> list = new ArrayList<>();
+            list.add(new CPDFCertAttrDataItem(getString(R.string.tools_reader_pdf_info_abstract)));
+            list.addAll(CertAttrDatas.getAbstractInfo(getContext(), cpdfx509));
+            list.add(new CPDFCertAttrDataItem(getString(R.string.tools_details)));
+            list.addAll(CertAttrDatas.getCertAttrDetailInfoList(getContext(), cpdfx509));
+            attrListAdapter.setList(list);
+        }
+    }
 }

+ 39 - 26
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/CertDigitalSignInfoDialog.java

@@ -27,14 +27,15 @@ import com.compdfkit.core.document.signature.CPDFSignature;
 import com.compdfkit.core.document.signature.CPDFSigner;
 import com.compdfkit.core.document.signature.CPDFX509;
 import com.compdfkit.tools.R;
-import com.compdfkit.tools.common.utils.CLog;
+import com.compdfkit.tools.common.basic.fragment.CBasicBottomSheetDialogFragment;
 import com.compdfkit.tools.common.utils.date.CDateUtil;
 import com.compdfkit.tools.common.utils.dialog.CDialogFragmentUtil;
 import com.compdfkit.tools.signature.CertificateDigitalDatas;
+import com.compdfkit.tools.signature.SignatureStatus;
 import com.google.android.material.bottomsheet.BottomSheetBehavior;
 import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
 
-public class CertDigitalSignInfoDialog extends BottomSheetDialogFragment implements View.OnClickListener {
+public class CertDigitalSignInfoDialog extends CBasicBottomSheetDialogFragment implements View.OnClickListener {
 
     private AppCompatTextView tvTitle;
 
@@ -59,31 +60,36 @@ public class CertDigitalSignInfoDialog extends BottomSheetDialogFragment impleme
         return fragment;
     }
 
-    public void setDocument(CPDFDocument document){
+    public void setDocument(CPDFDocument document) {
         this.document = document;
     }
 
-    public void setPDFSignature(CPDFSignature signature){
+    public void setPDFSignature(CPDFSignature signature) {
         this.cpdfSignature = signature;
     }
 
     @Override
-    public void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setStyle(STYLE_NORMAL, R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle_TopCorners);
+    protected int getStyle() {
+        return R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle_TopCorners;
     }
 
     @Override
-    public void onStart() {
-        super.onStart();
-        BottomSheetBehavior<View> behavior = BottomSheetBehavior.from((View) getView().getParent());
-        CDialogFragmentUtil.setBottomSheetDialogFragmentFullScreen(getDialog(), behavior);
+    protected boolean draggable() {
+        return false;
     }
 
-    @Nullable
     @Override
-    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-        View view = inflater.inflate(R.layout.tools_sign_certificate_digital_sign_info_fragment, container, false);
+    protected boolean fullScreen() {
+        return true;
+    }
+
+    @Override
+    protected int layoutId() {
+        return R.layout.tools_sign_certificate_digital_sign_info_fragment;
+    }
+
+    @Override
+    protected void onCreateView(View view) {
         tvTitle = view.findViewById(R.id.tv_tool_bar_title);
         ivClose = view.findViewById(R.id.iv_tool_bar_close);
         tvFounder = view.findViewById(R.id.tv_sign_founder);
@@ -92,27 +98,33 @@ public class CertDigitalSignInfoDialog extends BottomSheetDialogFragment impleme
         tvSignStatement = view.findViewById(R.id.tv_sign_statement_info);
         ivClose.setOnClickListener(this);
         btnSignDetails.setOnClickListener(this);
-        return view;
     }
 
     @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
+    protected void onViewCreate() {
         tvTitle.setText(R.string.tools_view_digital_signature);
         if (cpdfSignature != null) {
             CPDFSigner[] signers = cpdfSignature.getSignerArr();
-            if (signers != null && signers.length >0){
+            if (signers != null && signers.length > 0) {
                 CPDFX509 cert = signers[0].getCert();
                 CPDFCertInfo certInfo = cert.getCertInfo();
-                String commonName = certInfo.getIssuer().getCommonName();
+                String commonName = certInfo.getSubject().getCommonName();
                 tvFounder.setText(commonName);
             }
             tvDateOfSignature.setText(CDateUtil.transformPDFDate(cpdfSignature.getDate()));
-            boolean signIsValid = CertificateDigitalDatas.verifySignIsValid(cpdfSignature, document);
-            if (signIsValid){
-                tvSignStatement.setText(R.string.tools_sign_is_valid_info);
-            }else {
-                tvSignStatement.setText(R.string.tools_sign_is_in_valid_info);
+            SignatureStatus status = CertificateDigitalDatas.verifySignatureStatus(document, cpdfSignature);
+            switch (status) {
+                case VALID:
+                    tvSignStatement.setText(R.string.tools_sign_is_valid_info);
+                    break;
+                case FAILURES:
+                    tvSignStatement.setText(R.string.tools_sign_is_in_valid_info);
+                    break;
+                case WRONG:
+                    tvSignStatement.setText(R.string.tools_sign_cert_has_expired);
+                    break;
+                default:
+                    break;
             }
         }
     }
@@ -121,8 +133,9 @@ public class CertDigitalSignInfoDialog extends BottomSheetDialogFragment impleme
     public void onClick(View v) {
         if (v.getId() == R.id.iv_tool_bar_close) {
             dismiss();
-        } else if (v.getId() == R.id.btn_cert_detail){
-
+        } else if (v.getId() == R.id.btn_cert_detail) {
+            CertDetailsDialog detailsDialog = CertDetailsDialog.newInstance(cpdfSignature);
+            detailsDialog.show(getChildFragmentManager(), "certDetailDialog");
         }
     }
 }

+ 26 - 22
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/signlist/CPDFCertDigitalSignListDialog.java

@@ -15,15 +15,16 @@ import androidx.recyclerview.widget.RecyclerView;
 import com.compdfkit.core.document.CPDFDocument;
 import com.compdfkit.core.document.signature.CPDFSignature;
 import com.compdfkit.tools.R;
+import com.compdfkit.tools.common.basic.fragment.CBasicBottomSheetDialogFragment;
 import com.compdfkit.tools.common.utils.CLog;
 import com.compdfkit.tools.common.utils.dialog.CAlertDialog;
 import com.compdfkit.tools.common.utils.dialog.CDialogFragmentUtil;
-import com.compdfkit.tools.common.utils.threadpools.CThreadPoolUtils;
 import com.compdfkit.tools.common.utils.threadpools.SimpleBackgroundTask;
 import com.compdfkit.tools.common.utils.viewutils.CViewUtils;
 import com.compdfkit.tools.common.views.CToolBar;
 import com.compdfkit.tools.common.views.pdfview.CPDFViewCtrl;
 import com.compdfkit.tools.signature.CertificateDigitalDatas;
+import com.compdfkit.tools.signature.SignatureStatus;
 import com.compdfkit.tools.signature.bean.CPDFSignatureItemData;
 import com.compdfkit.tools.signature.info.CertDigitalSignInfoDialog;
 import com.compdfkit.tools.signature.info.signlist.adapter.CertDigitalSignListAdapter;
@@ -33,7 +34,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
 import java.util.ArrayList;
 import java.util.List;
 
-public class CPDFCertDigitalSignListDialog extends BottomSheetDialogFragment {
+public class CPDFCertDigitalSignListDialog extends CBasicBottomSheetDialogFragment {
 
     private RecyclerView recyclerView;
 
@@ -58,36 +59,42 @@ public class CPDFCertDigitalSignListDialog extends BottomSheetDialogFragment {
     }
 
     @Override
-    public void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setStyle(STYLE_NORMAL, R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle);
+    protected int getStyle() {
+        return R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle;
     }
 
     @Override
-    public void onStart() {
-        super.onStart();
-        BottomSheetBehavior<View> behavior = BottomSheetBehavior.from((View) getView().getParent());
-        CDialogFragmentUtil.setBottomSheetDialogFragmentFullScreen(getDialog(), behavior);
-        CDialogFragmentUtil.setDimAmount(getDialog(), CViewUtils.isLandScape(getContext()) ? 0.2F : 0F);
+    protected boolean fullScreen() {
+        return true;
     }
 
-    @Nullable
     @Override
-    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-        View view = inflater.inflate(R.layout.tools_sign_cert_digital_sign_list_fragment, container, false);
+    protected boolean draggable() {
+        return false;
+    }
+
+    @Override
+    protected float dimAmount() {
+        return CViewUtils.isLandScape(getContext()) ? 0.2F : 0F;
+    }
+
+    @Override
+    protected int layoutId() {
+        return R.layout.tools_sign_cert_digital_sign_list_fragment;
+    }
+
+    @Override
+    protected void onCreateView(View view) {
         recyclerView = view.findViewById(R.id.recycler_view);
         toolBar = view.findViewById(R.id.tool_bar);
         progressBar = view.findViewById(R.id.progress_bar);
         toolBar.setBackBtnClickListener(v -> {
             dismiss();
         });
-        return view;
     }
 
-
     @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
+    protected void onViewCreate() {
         recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
         signListAdapter = new CertDigitalSignListAdapter(pdfView.getCPdfReaderView().getPDFDocument());
         recyclerView.setAdapter(signListAdapter);
@@ -127,10 +134,8 @@ public class CPDFCertDigitalSignListDialog extends BottomSheetDialogFragment {
                 List<CPDFSignatureItemData> itemDataList = new ArrayList<>();
                 List<CPDFSignature> list = CertificateDigitalDatas.getDigitalSignList(document);
                 for (CPDFSignature signature : list) {
-                    long time = System.currentTimeMillis();
-                    boolean isValid = CertificateDigitalDatas.verifySignIsValid(signature, document);
-                    CLog.e("耗时", System.currentTimeMillis()- time+"ms");
-                    itemDataList.add(new CPDFSignatureItemData(signature, isValid));
+                    SignatureStatus status = CertificateDigitalDatas.verifySignatureStatus(document, signature);
+                    itemDataList.add(new CPDFSignatureItemData(signature, status));
                 }
                 return itemDataList;
             }
@@ -143,6 +148,5 @@ public class CPDFCertDigitalSignListDialog extends BottomSheetDialogFragment {
             }
         };
         task.execute();
-
     }
 }

+ 19 - 13
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/signlist/adapter/CertDigitalSignListAdapter.java

@@ -6,14 +6,11 @@ import android.view.ViewGroup;
 
 import com.compdfkit.core.document.CPDFDocument;
 import com.compdfkit.core.document.signature.CPDFCertInfo;
-import com.compdfkit.core.document.signature.CPDFSignature;
 import com.compdfkit.core.document.signature.CPDFSigner;
 import com.compdfkit.tools.R;
-import com.compdfkit.tools.common.utils.CUriUtil;
 import com.compdfkit.tools.common.utils.adapter.CBaseQuickAdapter;
 import com.compdfkit.tools.common.utils.adapter.CBaseQuickViewHolder;
 import com.compdfkit.tools.common.utils.date.CDateUtil;
-import com.compdfkit.tools.signature.CertificateDigitalDatas;
 import com.compdfkit.tools.signature.bean.CPDFSignatureItemData;
 
 
@@ -35,16 +32,25 @@ public class CertDigitalSignListAdapter extends CBaseQuickAdapter<CPDFSignatureI
         Context context = holder.itemView.getContext();
         CPDFSigner[] signers = item.getSignature().getSignerArr();
         CPDFCertInfo certInfos = signers[0].getCert().getCertInfo();
-        if (item.isValid()) {
-            holder.setText(R.id.tv_sign_status, R.string.tools_authentication_successful);
-            holder.setImageResource(R.id.iv_icon, R.drawable.tools_ic_digital_sign_is_valid);
-            holder.setText(R.id.tv_sign_desc, context.getString(R.string.tools_valid_signature) + "," +
-                    context.getString(R.string.tools_signed_by) + " " + certInfos.getIssuer().getCommonName());
-        } else {
-            holder.setText(R.id.tv_sign_status, R.string.tools_authentication_failures);
-            holder.setImageResource(R.id.iv_icon, R.drawable.tools_ic_digital_sign_is_failures);
-            holder.setText(R.id.tv_sign_desc, context.getString(R.string.tools_valid_in_signature) + "," +
-                    context.getString(R.string.tools_signed_by) + " " + certInfos.getIssuer().getCommonName());
+        switch (item.getSignatureStatus()){
+            case VALID:
+                holder.setText(R.id.tv_sign_status, R.string.tools_authentication_successful);
+                holder.setImageResource(R.id.iv_icon, R.drawable.tools_ic_digital_sign_is_valid);
+                holder.setText(R.id.tv_sign_desc, context.getString(R.string.tools_valid_signature) + "," +
+                        context.getString(R.string.tools_signed_by) + " " + certInfos.getSubject().getCommonName());
+                break;
+            case FAILURES:
+                holder.setText(R.id.tv_sign_status, R.string.tools_authentication_failures);
+                holder.setImageResource(R.id.iv_icon, R.drawable.tools_ic_digital_sign_is_failures);
+                holder.setText(R.id.tv_sign_desc, context.getString(R.string.tools_valid_in_signature) + "," +
+                        context.getString(R.string.tools_signed_by) + " " + certInfos.getSubject().getCommonName());
+                break;
+            case WRONG:
+                holder.setText(R.id.tv_sign_status, R.string.tools_authentication_wailures);
+                holder.setImageResource(R.id.iv_icon, R.drawable.tools_ic_digital_sign_is_wrong);
+                holder.setText(R.id.tv_sign_desc, context.getString(R.string.tools_valid_in_signature) + "," +
+                        context.getString(R.string.tools_signed_by) + " " + certInfos.getSubject().getCommonName());
+                break;
         }
         if (TextUtils.isEmpty(item.getSignature().getDate())) {
             holder.setText(R.id.tv_sign_date, "");

+ 3 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/pdfproperties/pdfsign/CDigitalSignStyleData.java

@@ -16,7 +16,9 @@ import com.compdfkit.core.document.CPDFSdk;
 import com.compdfkit.tools.R;
 import com.compdfkit.tools.common.utils.date.CDateUtil;
 
-public class CDigitalSignStyleData {
+import java.io.Serializable;
+
+public class CDigitalSignStyleData implements Serializable {
 
 
     public CDigitalSignStyleData(){

+ 3 - 6
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/pdfproperties/pdfsign/CDigitalSignatureWidgetImpl.java

@@ -18,9 +18,7 @@ import com.compdfkit.core.annotation.form.CPDFSignatureWidget;
 import com.compdfkit.core.document.signature.CPDFCertInfo;
 import com.compdfkit.core.document.signature.CPDFSignature;
 import com.compdfkit.core.document.signature.CPDFSigner;
-import com.compdfkit.core.document.signature.CPDFX509;
 import com.compdfkit.tools.R;
-import com.compdfkit.tools.common.activity.CBasicActivity;
 import com.compdfkit.tools.common.utils.CFileUtils;
 import com.compdfkit.tools.common.utils.CToastUtil;
 import com.compdfkit.tools.common.utils.image.CBitmapUtil;
@@ -40,7 +38,7 @@ public class CDigitalSignatureWidgetImpl extends CPDFSignatureWidgetImpl {
     public void onSignatureWidgetFocused(CPDFSignatureWidget cpdfSignatureWidget) {
         CPDFSignature signature = readerView.getPDFDocument().getPdfSignature(cpdfSignatureWidget);
         CPDFSigner[]  signers = signature.getSignerArr();
-        if (signers != null && signers.length >0){
+        if (signature.isDigitalSigned()){
             CertDigitalSignInfoDialog signInfoDialog = CertDigitalSignInfoDialog.newInstance();
             signInfoDialog.setDocument(readerView.getPDFDocument());
             signInfoDialog.setPDFSignature(signature);
@@ -53,8 +51,7 @@ public class CDigitalSignatureWidgetImpl extends CPDFSignatureWidgetImpl {
         CPDFSelectDigitalSignatureDialog dialog = CPDFSelectDigitalSignatureDialog.newInstance();
         dialog.setCertDigitalSignListener((certFilePath, certPassword, signImagePath) -> {
             CPDFCertInfo certInfo = CertificateDigitalDatas.getCertInfo(certFilePath, certPassword);
-            CDigitalSignStylePreviewDialog previewDialog = CDigitalSignStylePreviewDialog.newInstance(signImagePath);
-            previewDialog.setCertInfo(certInfo);
+            CDigitalSignStylePreviewDialog previewDialog = CDigitalSignStylePreviewDialog.newInstance(signImagePath, certInfo.getSubject().getCommonName());
             previewDialog.setResultDigitalSignListener((digitalSignImagePath, styleData) -> {
                 try {
                     // set sign image
@@ -65,7 +62,7 @@ public class CDigitalSignatureWidgetImpl extends CPDFSignatureWidgetImpl {
                             CFileUtils.ROOT_FOLDER + "digitalSign" + File.separator + readerView.getPDFDocument().getFileName());
                     saveFile.getParentFile().mkdirs();
                     // sign this pdf document
-                    boolean result = CertificateDigitalDatas.signDocument(readerView.getPDFDocument(),
+                    boolean result = CertificateDigitalDatas.writeSignature(readerView.getPDFDocument(),
                             cpdfSignatureWidget, styleData,
                             certFilePath, certPassword, saveFile.getAbsolutePath());
                     if (result){

+ 32 - 28
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/preview/CDigitalSignStylePreviewDialog.java

@@ -31,20 +31,22 @@ import androidx.appcompat.widget.AppCompatTextView;
 import com.compdfkit.core.document.signature.CPDFCertInfo;
 import com.compdfkit.tools.R;
 import com.compdfkit.tools.annotation.pdfproperties.pdfsignature.data.CSignatureDatas;
+import com.compdfkit.tools.common.basic.fragment.CBasicBottomSheetDialogFragment;
 import com.compdfkit.tools.common.utils.dialog.CDialogFragmentUtil;
 import com.compdfkit.tools.common.utils.viewutils.CViewUtils;
 import com.compdfkit.tools.common.views.CToolBar;
-import com.compdfkit.tools.signature.preview.view.CSignStylePositionView;
-import com.compdfkit.tools.signature.preview.view.CSignStyleReasonView;
 import com.compdfkit.tools.signature.pdfproperties.pdfsign.CDigitalSignStyleData;
 import com.compdfkit.tools.signature.pdfproperties.pdfsign.CDigitalSignStylePreviewView;
+import com.compdfkit.tools.signature.preview.view.CSignStylePositionView;
+import com.compdfkit.tools.signature.preview.view.CSignStyleReasonView;
 import com.google.android.material.bottomsheet.BottomSheetBehavior;
 import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
 
 
-public class CDigitalSignStylePreviewDialog extends BottomSheetDialogFragment implements View.OnClickListener {
+public class CDigitalSignStylePreviewDialog extends CBasicBottomSheetDialogFragment implements View.OnClickListener {
 
     public static final String EXTRA_SIGN_IMAGE_PATH = "extra_sign_image_path";
+    public static final String EXTRA_COMMON_NAME = "extra_common_name";
 
     private CDigitalSignStylePreviewView previewView;
 
@@ -90,20 +92,15 @@ public class CDigitalSignStylePreviewDialog extends BottomSheetDialogFragment im
 
     private COnResultDigitalSignListener resultDigitalSignListener;
 
-    private CPDFCertInfo certInfo;
-
-    public static CDigitalSignStylePreviewDialog newInstance(String signImagePath) {
+    public static CDigitalSignStylePreviewDialog newInstance(String signImagePath, String commonName) {
         Bundle args = new Bundle();
         args.putString(EXTRA_SIGN_IMAGE_PATH, signImagePath);
+        args.putString(EXTRA_COMMON_NAME, commonName);
         CDigitalSignStylePreviewDialog fragment = new CDigitalSignStylePreviewDialog();
         fragment.setArguments(args);
         return fragment;
     }
 
-    public void setCertInfo(CPDFCertInfo certInfo){
-        this.certInfo = certInfo;
-    }
-
     @NonNull
     @Override
     public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
@@ -122,24 +119,32 @@ public class CDigitalSignStylePreviewDialog extends BottomSheetDialogFragment im
     }
 
     @Override
-    public void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setStyle(STYLE_NORMAL, R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle_FillScreen);
+    protected int getStyle() {
+        return  R.style.Tools_Base_Theme_BasicBottomSheetDialogStyle;
+    }
+
+    @Override
+    protected boolean fullScreen() {
+        return true;
+    }
+
+    @Override
+    protected float dimAmount() {
+        return CViewUtils.isLandScape(getContext()) ? 0.2F : 0F;
+    }
+
+    @Override
+    protected boolean draggable() {
+        return false;
     }
 
     @Override
-    public void onStart() {
-        super.onStart();
-        BottomSheetBehavior<View> behavior = BottomSheetBehavior.from((View) getView().getParent());
-        CDialogFragmentUtil.setBottomSheetDialogFragmentFullScreen(getDialog(), behavior);
-        CDialogFragmentUtil.setDimAmount(getDialog(), 0F);
-        behavior.setDraggable(false);
+    protected int layoutId() {
+        return R.layout.tools_sign_style_preview_dialog;
     }
 
-    @Nullable
     @Override
-    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-        View view = inflater.inflate(R.layout.tools_sign_style_preview_dialog, container, false);
+    protected void onCreateView(View view) {
         previewView = view.findViewById(R.id.digital_sign_preview);
         tvPosition = view.findViewById(R.id.tv_position);
         tvReason = view.findViewById(R.id.tv_reason);
@@ -160,12 +165,10 @@ public class CDigitalSignStylePreviewDialog extends BottomSheetDialogFragment im
         ivAlignmentRight = view.findViewById(R.id.iv_alignment_right);
         llAlignment = view.findViewById(R.id.ll_alignment_type);
         tvAlignment = view.findViewById(R.id.tv_alignment);
-        return view;
     }
 
     @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
+    protected void onViewCreate() {
         initListener();
         initData();
     }
@@ -217,9 +220,10 @@ public class CDigitalSignStylePreviewDialog extends BottomSheetDialogFragment im
     private void initData(){
         String signImagePath = getArguments().getString(EXTRA_SIGN_IMAGE_PATH, "");
         CDigitalSignStyleData data = CDigitalSignStyleData.defaultConfig(signImagePath);
-        if (certInfo != null) {
-            data.setDigtinguishableName(certInfo.getIssuer().getCommonName());
-            data.setName(certInfo.getIssuer().getCommonName());
+        if (getArguments() != null && !TextUtils.isEmpty(getArguments().getString(EXTRA_COMMON_NAME))) {
+            String commonName = getArguments().getString(EXTRA_COMMON_NAME);
+            data.setDigtinguishableName(commonName);
+            data.setName(commonName);
         }
         previewView.setPreviewData(data);
         previewView.setShowName(cbName.isChecked());

+ 0 - 5
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/preview/view/CSignStylePositionView.java

@@ -10,15 +10,10 @@
 package com.compdfkit.tools.signature.preview.view;
 
 import android.content.Context;
-import android.text.Editable;
-import android.text.TextUtils;
-import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.CompoundButton;
-import android.widget.EditText;
 import android.widget.FrameLayout;
-import android.widget.RadioGroup;
 import android.widget.Switch;
 
 import androidx.annotation.NonNull;

+ 0 - 2
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/preview/view/CSignStyleReasonView.java

@@ -12,7 +12,6 @@ package com.compdfkit.tools.signature.preview.view;
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.CompoundButton;
 import android.widget.FrameLayout;
@@ -21,7 +20,6 @@ import android.widget.Switch;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.appcompat.widget.AppCompatRadioButton;
 
 import com.compdfkit.tools.R;
 

+ 7 - 16
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/verify/view/CVerifySignStatusView.java

@@ -24,6 +24,7 @@ import androidx.fragment.app.FragmentActivity;
 
 import com.compdfkit.tools.R;
 import com.compdfkit.tools.common.views.pdfview.CPDFViewCtrl;
+import com.compdfkit.tools.signature.SignatureStatus;
 import com.compdfkit.tools.signature.info.signlist.CPDFCertDigitalSignListDialog;
 
 public class CVerifySignStatusView extends FrameLayout {
@@ -34,7 +35,7 @@ public class CVerifySignStatusView extends FrameLayout {
 
     private AppCompatButton btnDetails;
 
-    private Status status;
+    private SignatureStatus status;
 
     private CPDFViewCtrl pdfView;
 
@@ -74,23 +75,23 @@ public class CVerifySignStatusView extends FrameLayout {
     private void initAttr(Context context, AttributeSet attrs) {
         TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CVerifySignStatusView);
         if (typedArray != null) {
-            int statusFlag = typedArray.getInt(R.styleable.CVerifySignStatusView_status, Status.VALID.ordinal());
+            int statusFlag = typedArray.getInt(R.styleable.CVerifySignStatusView_status, SignatureStatus.VALID.ordinal());
             switch (statusFlag) {
                 case 1:
-                    status = Status.FAILURES;
+                    status = SignatureStatus.FAILURES;
                     break;
                 case 2:
-                    status = Status.WRONG;
+                    status = SignatureStatus.WRONG;
                     break;
                 default:
-                    status = Status.VALID;
+                    status = SignatureStatus.VALID;
                     break;
             }
             typedArray.recycle();
         }
     }
 
-    public void setStatus(Status status) {
+    public void setStatus(SignatureStatus status) {
         this.status = status;
         updateStatus();
     }
@@ -113,14 +114,4 @@ public class CVerifySignStatusView extends FrameLayout {
                 break;
         }
     }
-
-
-    public enum Status {
-
-        VALID,
-
-        FAILURES,
-
-        WRONG
-    }
 }

File diff suppressed because it is too large
+ 10 - 0
ComPDFKit_Tools/src/main/res/drawable-night/tools_ic_digital_signature.xml


+ 0 - 1
ComPDFKit_Tools/src/main/res/layout-land/tools_sign_style_preview_main.xml

@@ -3,7 +3,6 @@
 
 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="wrap_content">
 

+ 7 - 243
ComPDFKit_Tools/src/main/res/layout/tools_sign_certificate_attributes_fragment.xml

@@ -14,251 +14,15 @@
         android:title="@string/tools_digital_sign_attr"
         app:layout_constraintTop_toTopOf="parent" />
 
-    <ScrollView
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/recycler_view"
         android:layout_width="match_parent"
         android:layout_height="0dp"
+        app:layout_constraintTop_toBottomOf="@id/tool_bar"
         app:layout_constraintBottom_toBottomOf="parent"
-        android:fillViewport="true"
-        app:layout_constraintTop_toBottomOf="@id/tool_bar">
-
-        <androidx.constraintlayout.widget.ConstraintLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-
-
-            <androidx.constraintlayout.widget.Guideline
-                android:id="@+id/guide_start"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:orientation="vertical"
-                app:layout_constraintGuide_begin="16dp" />
-
-            <androidx.constraintlayout.widget.Barrier
-                android:id="@+id/barrier_title"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                app:barrierDirection="end"
-                app:constraint_referenced_ids="tv_version_title,tv_sign_orithm_title,tv_thematic_title,tv_product_key_title,tv_validity_period_title,tv_cert_policy_title,tv_crl_distri_point_title" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:id="@+id/tv_version_title"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="16dp"
-                android:text="@string/tools_version"
-                android:textStyle="bold"
-                android:textColor="@color/tools_text_color_secondary"
-                app:layout_constraintStart_toStartOf="@id/guide_start"
-                app:layout_constraintTop_toTopOf="parent" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:id="@+id/tv_sign_orithm_title"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="24dp"
-                android:textStyle="bold"
-                android:text="@string/tools_signature_orithm"
-                android:textColor="@color/tools_text_color_secondary"
-                app:layout_constraintStart_toStartOf="@id/guide_start"
-                app:layout_constraintTop_toBottomOf="@id/tv_version_title" />
-
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:id="@+id/tv_thematic_title"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="24dp"
-                android:textStyle="bold"
-                android:text="@string/tools_thematic"
-                android:textColor="@color/tools_text_color_secondary"
-                app:layout_constraintStart_toStartOf="@id/guide_start"
-                app:layout_constraintTop_toBottomOf="@id/barrier_sign_orithm" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:id="@+id/tv_product_key_title"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="24dp"
-                android:text="@string/tools_product_key"
-                android:textStyle="bold"
-                android:textColor="@color/tools_text_color_secondary"
-                app:layout_constraintStart_toStartOf="@id/guide_start"
-                app:layout_constraintTop_toBottomOf="@id/barrier_thematic" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:id="@+id/tv_validity_period_title"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="24dp"
-                android:text="@string/tools_validity_period"
-                android:textStyle="bold"
-                android:textColor="@color/tools_text_color_secondary"
-                app:layout_constraintStart_toStartOf="@id/guide_start"
-                app:layout_constraintTop_toBottomOf="@id/tv_product_key_title" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:id="@+id/tv_cert_policy_title"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="24dp"
-                android:textStyle="bold"
-
-                android:text="@string/tools_certificate_policy"
-                android:textColor="@color/tools_text_color_secondary"
-                app:layout_constraintStart_toStartOf="@id/guide_start"
-                app:layout_constraintTop_toBottomOf="@id/barrier_validity_period" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:id="@+id/tv_crl_distri_point_title"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="24dp"
-                android:textStyle="bold"
-                android:text="@string/tools_crl_distri_point"
-                android:textColor="@color/tools_text_color_secondary"
-                app:layout_constraintStart_toStartOf="@id/guide_start"
-                app:layout_constraintTop_toBottomOf="@id/barrier_cert_policy" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:id="@+id/tv_version_value"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="8dp"
-                android:layout_marginTop="24dp"
-                android:textColor="@color/tools_text_color_secondary"
-                app:layout_constrainedWidth="true"
-                app:layout_constraintBaseline_toBaselineOf="@id/tv_version_title"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintHorizontal_bias="0"
-                app:layout_constraintStart_toEndOf="@id/barrier_title"
-                tools:text="V3" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:id="@+id/tv_sign_orithm_value"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="8dp"
-                android:layout_marginTop="24dp"
-                android:textColor="@color/tools_text_color_secondary"
-                app:layout_constrainedWidth="true"
-                app:layout_constraintBaseline_toBaselineOf="@id/tv_sign_orithm_title"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintHorizontal_bias="0"
-                app:layout_constraintStart_toEndOf="@id/barrier_title"
-                tools:text="SHA - 256 with RSA encryption (1.2.840.113549.1.11)" />
-
-            <androidx.constraintlayout.widget.Barrier
-                android:id="@+id/barrier_sign_orithm"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                app:barrierDirection="bottom"
-                app:constraint_referenced_ids="tv_sign_orithm_title,tv_sign_orithm_value" />
-
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:id="@+id/tv_thematic_value"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="8dp"
-                android:layout_marginTop="24dp"
-                android:textColor="@color/tools_text_color_secondary"
-                app:layout_constrainedWidth="true"
-                app:layout_constraintBaseline_toBaselineOf="@id/tv_thematic_title"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintHorizontal_bias="0"
-                app:layout_constraintStart_toEndOf="@id/barrier_title"
-                tools:text="C=CN,O=ComPDFKit" />
-
-            <androidx.constraintlayout.widget.Barrier
-                android:id="@+id/barrier_thematic"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                app:barrierDirection="bottom"
-                app:constraint_referenced_ids="tv_thematic_title,tv_thematic_value" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:id="@+id/tv_product_key_value"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="8dp"
-                android:layout_marginTop="24dp"
-                android:textColor="@color/tools_text_color_secondary"
-                app:layout_constrainedWidth="true"
-                app:layout_constraintBaseline_toBaselineOf="@id/tv_product_key_title"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintHorizontal_bias="0"
-                app:layout_constraintStart_toEndOf="@id/barrier_title"
-                tools:text="000000000000000000" />
-
-            <androidx.constraintlayout.widget.Barrier
-                android:id="@+id/barrier_product_key"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                app:barrierDirection="bottom"
-                app:constraint_referenced_ids="tv_product_key_title,tv_product_key_value" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:id="@+id/tv_validity_period_value"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="8dp"
-                android:layout_marginTop="24dp"
-                android:textColor="@color/tools_text_color_secondary"
-                app:layout_constrainedWidth="true"
-                app:layout_constraintBaseline_toBaselineOf="@id/tv_validity_period_title"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintHorizontal_bias="0"
-                app:layout_constraintStart_toEndOf="@id/barrier_title"
-                tools:text="2023-01-01 10:00:00 +8`00`" />
-
-            <androidx.constraintlayout.widget.Barrier
-                android:id="@+id/barrier_validity_period"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                app:barrierDirection="bottom"
-                app:constraint_referenced_ids="tv_validity_period_title,tv_validity_period_value" />
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:id="@+id/tv_cert_policy_value"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="8dp"
-                android:layout_marginTop="24dp"
-                android:textColor="@color/tools_text_color_secondary"
-                app:layout_constrainedWidth="true"
-                app:layout_constraintBaseline_toBaselineOf="@id/tv_cert_policy_title"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintHorizontal_bias="0"
-                app:layout_constraintStart_toEndOf="@id/barrier_title"
-                tools:text="Windows Certificate Policy" />
-
-            <androidx.constraintlayout.widget.Barrier
-                android:id="@+id/barrier_cert_policy"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                app:barrierDirection="bottom"
-                app:constraint_referenced_ids="tv_cert_policy_title,tv_cert_policy_value" />
-
-
-            <androidx.appcompat.widget.AppCompatTextView
-                android:id="@+id/tv_crl_distri_value"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="8dp"
-                android:layout_marginTop="24dp"
-                android:textColor="@color/tools_text_color_secondary"
-                app:layout_constrainedWidth="true"
-                app:layout_constraintBaseline_toBaselineOf="@id/tv_crl_distri_point_title"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintHorizontal_bias="0"
-                app:layout_constraintStart_toEndOf="@id/barrier_title"
-                tools:text="/" />
-
-
-        </androidx.constraintlayout.widget.ConstraintLayout>
-
-
-    </ScrollView>
-
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        tools:listitem="@layout/tools_sign_certificate_attributes_list_item"
+        />
 
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 25 - 0
ComPDFKit_Tools/src/main/res/layout/tools_sign_certificate_attributes_list_head_item.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginVertical="16dp"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+
+    <androidx.appcompat.widget.AppCompatTextView
+        android:id="@+id/tv_head"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/tools_version"
+        android:textStyle="bold"
+        android:textSize="18sp"
+        android:textColor="@color/tools_text_color_primary"
+        app:layout_constraintStart_toStartOf="parent"
+        android:layout_marginStart="16dp"
+        app:layout_constraintHorizontal_bias="0"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintTop_toTopOf="parent" />
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 47 - 0
ComPDFKit_Tools/src/main/res/layout/tools_sign_certificate_attributes_list_item.xml

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginVertical="16dp"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/guide"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        app:layout_constraintGuide_percent="0.35" />
+
+    <androidx.appcompat.widget.AppCompatTextView
+        android:id="@+id/tv_attr_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/tools_version"
+        android:textStyle="bold"
+        android:textColor="@color/tools_text_color_secondary"
+        app:layout_constraintStart_toStartOf="parent"
+        android:layout_marginStart="16dp"
+        app:layout_constraintEnd_toEndOf="@id/guide"
+        app:layout_constraintHorizontal_bias="0"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <androidx.appcompat.widget.AppCompatTextView
+        android:id="@+id/tv_attr_value"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:layout_marginTop="24dp"
+        android:textColor="@color/tools_text_color_secondary"
+        app:layout_constrainedWidth="true"
+        android:layout_marginEnd="16dp"
+        app:layout_constraintBaseline_toBaselineOf="@id/tv_attr_title"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@id/guide"
+        app:layout_constraintHorizontal_bias="0"
+        tools:text="V3" />
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 29 - 0
ComPDFKit_Tools/src/main/res/layout/tools_sign_certificate_details_dialog.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/tools_annot_style_dialog_window_bg">
+
+    <com.compdfkit.tools.common.views.CToolBar
+        android:id="@+id/tool_bar"
+        android:layout_width="match_parent"
+        android:layout_height="?attr/actionBarSize"
+        android:elevation="4dp"
+        android:title="@string/tools_cert_details"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/recycler_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:layout_constraintVertical_bias="0"
+        tools:itemCount="50"
+        app:layout_constrainedHeight="true"
+        tools:listitem="@layout/tools_sign_certificate_details_list_item"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/tool_bar" />
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 45 - 0
ComPDFKit_Tools/src/main/res/layout/tools_sign_certificate_details_list_item.xml

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/cl_root"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:foreground="@drawable/tools_common_btn_rectangle_ripple"
+    android:minHeight="32dp">
+
+    <androidx.appcompat.widget.AppCompatImageView
+        android:id="@+id/iv_item_arrow"
+        android:layout_width="32dp"
+        android:layout_height="32dp"
+        android:layout_marginStart="4dp"
+        android:padding="8dp"
+        android:visibility="visible"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:srcCompat="@drawable/tools_ic_right"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintHorizontal_bias="0"
+        app:tint="@color/tools_text_color_primary"
+        app:layout_constraintEnd_toStartOf="@id/tv_item_title"
+        tools:visibility="visible" />
+
+    <androidx.appcompat.widget.AppCompatTextView
+        android:id="@+id/tv_item_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="8dp"
+        android:paddingVertical="8dp"
+        android:textColor="@color/tools_text_color_secondary"
+        android:textSize="14sp"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0"
+        app:layout_constraintStart_toEndOf="@+id/iv_item_arrow"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:text="C=TW,O=KdanMobile,OU=Test..C=TW,TW,O=KdanMobile,OU=Test..C=TW," />
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 1 - 0
ComPDFKit_Tools/src/main/res/layout/tools_sign_certificate_digital_sign_info_fragment.xml

@@ -113,6 +113,7 @@
         android:layout_marginHorizontal="16dp"
         android:layout_marginTop="16dp"
         app:layout_constrainedWidth="true"
+        android:textColor="@color/tools_text_color_primary"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintHorizontal_bias="0"
         app:layout_constraintStart_toStartOf="parent"

+ 0 - 1
ComPDFKit_Tools/src/main/res/layout/tools_sign_create_cert_digital_id_fragment.xml

@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@drawable/tools_annot_style_dialog_window_bg">

+ 0 - 1
ComPDFKit_Tools/src/main/res/layout/tools_sign_create_cert_digital_id_info_layout.xml

@@ -2,7 +2,6 @@
 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="wrap_content">
 

+ 0 - 1
ComPDFKit_Tools/src/main/res/layout/tools_sign_style_preview_dialog.xml

@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@color/tools_style_content_bg">

+ 0 - 1
ComPDFKit_Tools/src/main/res/layout/tools_sign_style_preview_main.xml

@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:id="@+id/sl_main"
     android:layout_height="wrap_content">

+ 1 - 1
ComPDFKit_Tools/src/main/res/layout/tools_sign_verify_sign_status_view.xml

@@ -25,7 +25,7 @@
         android:layout_marginStart="8dp"
         android:paddingVertical="4dp"
         android:text="@string/tools_sign_is_valid_info"
-        android:textColor="@color/tools_text_color_primary"
+        android:textColor="@color/tools_annot_icon_select_color"
         android:textSize="14sp"
         app:layout_constrainedWidth="true"
         app:layout_constraintBottom_toBottomOf="parent"

+ 26 - 3
ComPDFKit_Tools/src/main/res/values/tools_strings.xml

@@ -359,23 +359,46 @@
     <string name="tools_import_digital_desc">Browse a digital ID file. Digital ID cards are password-protected. If you do not know the password, you cannot obtain a digital ID card.</string>
     <string name="tools_close">Close</string>
 
+    <string name="tools_permission_tips_title">Permissions Required</string>
+    <string name="tools_permission_tips_msg">This app may not work correctly without the requested permissions. Open the app settings screen to modify app permissions</string>
+
     <!--    V2.0.0 Digital signature pending confirmation-->
+    <string name="tools_cert_details">Certificate Details</string>
     <string name="tools_authentication_successful">Authentication Successful</string>
     <string name="tools_authentication_failures">Authentication Failures</string>
+    <string name="tools_authentication_wailures">Authentication Wrong</string>
     <string name="tools_valid_signature">Valid signature</string>
     <string name="tools_valid_in_signature">InValid signature</string>
     <string name="tools_signed_by">Signed by</string>
     <string name="tools_view_digital_signature">View Digital Signature</string>
     <string name="tools_signature_message">Signature Message</string>
     <string name="tools_digital_sign_attr">Digital Signature Attributes</string>
-    <string name="tools_version">Version:</string>
     <string name="tools_signature_orithm">Signature...orithm:</string>
     <string name="tools_thematic">Thematic:</string>
     <string name="tools_product_key">Product Key:</string>
     <string name="tools_validity_period">Validity period:</string>
-    <string name="tools_certificate_policy">Certificate Policy:</string>
-    <string name="tools_crl_distri_point">CRL distri...point:</string>
     <string name="tools_digital_sign_success">Signature successful</string>
     <string name="tools_signature_time">Signature Time:</string>
 
+    <string name="tools_version">Version</string>
+    <string name="tools_signature_algorithm">signature algorithm</string>
+
+    <string name="tools_subject">Subject</string>
+    <string name="tools_issuer">Issuer</string>
+    <string name="tools_valid_start_date">Valid start date</string>
+    <string name="tools_valid_until_date">Valid until date</string>
+    <string name="tools_expected_usage">expected usage</string>
+    <string name="tools_certificate_policy">Certificate Policy</string>
+    <string name="tools_crl_distribution_point">CRL distribution point</string>
+    <string name="tools_auth_info_access">Authority Information Access</string>
+    <string name="tools_issuing_auth_key_identifier">Issuing Authority Key Identifier</string>
+    <string name="tools_subject_key_identifier">Subject Key Identifier</string>
+    <string name="tools_basic_limit">Basic limit</string>
+    <string name="tools_key_usage">Key usage</string>
+    <string name="tools_public_key">Public key</string>
+    <string name="tools_x_509_data">X.509 data</string>
+    <string name="tools_sha1_digest">SHA1 Digest</string>
+    <string name="tools_md5_digest">MD5 Digest</string>
+    <string name="tools_details">Details</string>
+
 </resources>

+ 0 - 1
ContentEditor/build.gradle

@@ -52,7 +52,6 @@ dependencies {
     implementation 'androidx.appcompat:appcompat:1.6.1'
     implementation 'com.google.android.material:material:1.8.0'
     implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
-    implementation 'pub.devrel:easypermissions:3.0.0'
     implementation project(':ComPDFKit_Tools')
 
 }

+ 23 - 34
ContentEditor/src/main/java/com/compdfkit/contenteditor/PDFEditSampleActivity.java

@@ -18,20 +18,20 @@ import android.content.Intent;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.view.View;
 import android.widget.Toast;
 
 import androidx.activity.result.ActivityResultLauncher;
 import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.compdfkit.contenteditor.databinding.EditPdfSampleActivityBinding;
 import com.compdfkit.core.edit.CPDFEditManager;
-import com.compdfkit.tools.common.activity.CBasicActivity;
+import com.compdfkit.tools.common.basic.activity.CBasicPDFActivity;
 import com.compdfkit.tools.common.contextmenu.CPDFContextMenuHelper;
 import com.compdfkit.tools.common.utils.CFileUtils;
+import com.compdfkit.tools.common.utils.CPermissionUtil;
+import com.compdfkit.tools.common.utils.activitycontracts.CSelectPDFDocumentResultContract;
 import com.compdfkit.tools.common.utils.dialog.CAlertDialog;
 import com.compdfkit.tools.common.utils.task.CExtractAssetFileTask;
 import com.compdfkit.tools.common.utils.threadpools.CThreadPoolUtils;
@@ -51,12 +51,7 @@ import com.compdfkit.ui.reader.CPDFReaderView;
 
 import java.util.ArrayList;
 
-import pub.devrel.easypermissions.AfterPermissionGranted;
-import pub.devrel.easypermissions.EasyPermissions;
-
-public class PDFEditSampleActivity extends CBasicActivity {
-
-    private final static int RC_PERMISSION_PERM = 111;
+public class PDFEditSampleActivity extends CBasicPDFActivity {
 
     /**
      * assets folder pdf file
@@ -67,13 +62,12 @@ public class PDFEditSampleActivity extends CBasicActivity {
 
     private CEditSampleScreenManager screenManager = new CEditSampleScreenManager();
 
-    private ActivityResultLauncher<Intent> selectDocumentLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
-        if (result.getData() != null && result.getData().getData() != null) {
+    private ActivityResultLauncher<Void> selectDocumentLauncher = registerForActivityResult(new CSelectPDFDocumentResultContract(), uri -> {
+        if (uri != null) {
             CPDFReaderView readerView = binding.pdfView.getCPdfReaderView();
             if (readerView != null && readerView.getEditManager() != null) {
                 readerView.getEditManager().endEdit();
             }
-            Uri uri = result.getData().getData();
             CFileUtils.takeUriPermission(this, uri);
             binding.pdfEditToolBar.resetStatus();
             setPreviewMode(CPreviewMode.Edit);
@@ -163,7 +157,7 @@ public class PDFEditSampleActivity extends CBasicActivity {
                 sharePDF(binding.pdfView);
             });
             menuWindow.addItem(R.drawable.tools_ic_new_file, R.string.tools_open_document, v1 -> {
-                if (hasStoragePermissions(STORAGE_PERMISSIONS)) {
+                if (CPermissionUtil.hasStoragePermissions(this)) {
                     selectDocument();
                 } else {
                     requestStoragePermissions();
@@ -197,9 +191,17 @@ public class PDFEditSampleActivity extends CBasicActivity {
 
     private void requestStoragePermissions(){
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){
-            startActivity(new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION));
+            CPermissionUtil.openManageAllFileAppSettings(this);
         }else {
-            EasyPermissions.requestPermissions(this, "request permission", REQUEST_EXTERNAL_PERMISSION, STORAGE_PERMISSIONS);
+            multiplePermissionResultLauncher.launch(STORAGE_PERMISSIONS, result -> {
+                if (CPermissionUtil.hasStoragePermissions(this)) {
+                    selectDocument();
+                }else {
+                    if (!CPermissionUtil.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)){
+                        showPermissionsRequiredDialog();
+                    }
+                }
+            });
         }
     }
 
@@ -269,11 +271,11 @@ public class PDFEditSampleActivity extends CBasicActivity {
             }
         }
         if (binding.pdfView.getCPdfReaderView().getPDFDocument() == null){
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+            selectDocumentLauncher.launch(null);
             return;
         }
         if (!binding.pdfView.getCPdfReaderView().getPDFDocument().hasChanges()){
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+            selectDocumentLauncher.launch(null);
             return;
         }
         CAlertDialog alertDialog = CAlertDialog.newInstance(getString(com.compdfkit.tools.R.string.tools_save_title), getString(com.compdfkit.tools.R.string.tools_save_message));
@@ -281,34 +283,21 @@ public class PDFEditSampleActivity extends CBasicActivity {
             //save pdf document
             binding.pdfView.savePDF((filePath, pdfUri) -> {
                 alertDialog.dismiss();
-                selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+                selectDocumentLauncher.launch(null);
             }, e -> {
                 alertDialog.dismiss();
-                selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+                selectDocumentLauncher.launch(null);
             });
         });
         alertDialog.setCancelClickListener(v -> {
             alertDialog.dismiss();
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+            selectDocumentLauncher.launch(null);
         });
         alertDialog.show(getSupportFragmentManager(), "alertDialog");
     }
 
-    @AfterPermissionGranted(RC_PERMISSION_PERM)
     private void onDoNext() {
-        if (!hasStoragePermissions()) {
-            EasyPermissions.requestPermissions(this, getString(R.string.edit_app_permission_storage), RC_PERMISSION_PERM, STORAGE_PERMISSIONS);
-        }
-    }
-
-    @Override
-    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
-        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
-        if (requestCode == REQUEST_EXTERNAL_PERMISSION) {
-            if (EasyPermissions.hasPermissions(this, android.Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
-                selectDocument();
-            }
-        }
+        multiplePermissionResultLauncher.launch(STORAGE_PERMISSIONS);
     }
 
     @Override

+ 2 - 3
DigitalSignature/build.gradle

@@ -21,7 +21,7 @@ android {
             android.applicationVariants.all { variant ->
                 variant.outputs.all {
                     if (outputFileName.toLowerCase().endsWith('unsigned.apk')) {
-                        outputFileName = "Viewer_ComPDFKit.apk"
+                        outputFileName = "DigitalSignature_ComPDFKit.apk"
                     }
                 }
             }
@@ -30,7 +30,7 @@ android {
             android.applicationVariants.all { variant ->
                 variant.outputs.all {
                     if (outputFileName.toLowerCase().endsWith('debug.apk')) {
-                        outputFileName = "Viewer_ComPDFKit.apk"
+                        outputFileName = "DigitalSignature_ComPDFKit.apk"
                     }
                 }
             }
@@ -50,5 +50,4 @@ dependencies {
     implementation 'com.google.android.material:material:1.8.0'
     implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
     implementation project(':ComPDFKit_Tools')
-    implementation 'pub.devrel:easypermissions:3.0.0'
 }

+ 3 - 3
DigitalSignature/src/androidTest/java/com/compdfkit/digitalsignature/ExampleInstrumentedTest.java

@@ -1,15 +1,15 @@
 package com.compdfkit.digitalsignature;
 
+import static org.junit.Assert.*;
+
 import android.content.Context;
 
-import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static org.junit.Assert.*;
-
 /**
  * Instrumented test, which will execute on an Android device.
  *

BIN
DigitalSignature/src/main/assets/4KDAN_adobe + chunghwa.pdf


BIN
DigitalSignature/src/main/assets/PDF32000_2008(2).pdf


BIN
DigitalSignature/src/main/assets/PSPDFKit_Widget_2_Widget.pdf


BIN
DigitalSignature/src/main/assets/測試樣張01_Signed拷貝.pdf


+ 5 - 5
DigitalSignature/src/main/java/com/compdfkit/digitalsignature/CViewerScreenStatusManager.java

@@ -13,15 +13,10 @@ package com.compdfkit.digitalsignature;
 import android.view.View;
 
 import androidx.constraintlayout.widget.ConstraintSet;
-import androidx.core.view.WindowCompat;
-import androidx.core.view.WindowInsetsCompat;
-import androidx.core.view.WindowInsetsControllerCompat;
-import androidx.fragment.app.FragmentActivity;
 
 import com.compdfkit.digitalsignature.databinding.SignaturesPdfSampleActivityBinding;
 import com.compdfkit.tools.common.utils.animation.CFillScreenManager;
 import com.compdfkit.tools.common.utils.animation.ConstraintSetUtils;
-import com.compdfkit.tools.common.utils.viewutils.CViewUtils;
 import com.compdfkit.tools.common.views.pdfview.CPreviewMode;
 
 public class CViewerScreenStatusManager {
@@ -87,4 +82,9 @@ public class CViewerScreenStatusManager {
         constraintSetUtils.apply(constraintSet, binding.getRoot());
     }
 
+    public void constraintHide(View view){
+        constraintSetUtils.hide(constraintSet, view);
+        constraintSetUtils.apply(constraintSet, binding.getRoot());
+    }
+
 }

+ 62 - 41
DigitalSignature/src/main/java/com/compdfkit/digitalsignature/PDFSignaturesSampleActivity.java

@@ -10,24 +10,23 @@
 package com.compdfkit.digitalsignature;
 
 import android.Manifest;
-import android.content.Intent;
-import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.view.View;
 
 import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
 
 import com.compdfkit.core.annotation.CPDFTextAnnotation;
 import com.compdfkit.core.annotation.form.CPDFSignatureWidget;
 import com.compdfkit.core.annotation.form.CPDFWidget;
+import com.compdfkit.core.document.CPDFDocument;
 import com.compdfkit.digitalsignature.databinding.SignaturesPdfSampleActivityBinding;
 import com.compdfkit.tools.annotation.pdfproperties.pdfnote.CPDFtextAnnotImpl;
-import com.compdfkit.tools.common.activity.CBasicActivity;
+import com.compdfkit.tools.common.basic.activity.CBasicPDFActivity;
 import com.compdfkit.tools.common.utils.CFileUtils;
+import com.compdfkit.tools.common.utils.CPermissionUtil;
+import com.compdfkit.tools.common.utils.activitycontracts.CSelectPDFDocumentResultContract;
+import com.compdfkit.tools.common.utils.dialog.CAlertDialog;
 import com.compdfkit.tools.common.utils.task.CExtractAssetFileTask;
 import com.compdfkit.tools.common.utils.window.CPopupMenuWindow;
 import com.compdfkit.tools.common.views.pdfbota.CPDFBOTA;
@@ -36,31 +35,31 @@ import com.compdfkit.tools.common.views.pdfbota.CPDFBotaFragmentTabs;
 import com.compdfkit.tools.common.views.pdfview.CPDFViewCtrl;
 import com.compdfkit.tools.common.views.pdfview.CPreviewMode;
 import com.compdfkit.tools.signature.CertificateDigitalDatas;
+import com.compdfkit.tools.signature.info.CertAttrDatas;
 import com.compdfkit.tools.signature.pdfproperties.pdfsign.CDigitalSignatureWidgetImpl;
-import com.compdfkit.tools.signature.info.signlist.CPDFCertDigitalSignListDialog;
-import com.compdfkit.tools.signature.verify.view.CVerifySignStatusView;
+import com.compdfkit.tools.signature.SignatureStatus;
 import com.compdfkit.tools.viewer.pdfsearch.CSearchResultDialogFragment;
 import com.compdfkit.ui.reader.CPDFReaderView;
 
 import java.util.ArrayList;
 
-import pub.devrel.easypermissions.EasyPermissions;
 
-public class PDFSignaturesSampleActivity extends CBasicActivity {
+public class PDFSignaturesSampleActivity extends CBasicPDFActivity {
 
     /**
      * assets folder pdf file
      */
-    public static final String QUICK_START_GUIDE = "PDF32000_2008(2).pdf";
+    public static final String QUICK_START_GUIDE = "測試樣張01_Signed拷貝_Widget.pdf";
 
     private SignaturesPdfSampleActivityBinding binding;
 
     private CViewerScreenStatusManager screenStatusManager;
 
-    private ActivityResultLauncher<Intent> selectDocumentLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
-        if (result.getData() != null && result.getData().getData() != null) {
-            Uri uri = result.getData().getData();
+    private ActivityResultLauncher<Void> selectDocumentLauncher = registerForActivityResult(new CSelectPDFDocumentResultContract(), uri -> {
+        if (uri != null) {
             CFileUtils.takeUriPermission(this, uri);
+            screenStatusManager.constraintHide(binding.signStatusView);
+            binding.signatureToolBar.reset();
             binding.pdfView.openPDF(uri);
         }
     });
@@ -97,13 +96,9 @@ public class PDFSignaturesSampleActivity extends CBasicActivity {
         binding.pdfToolBar.setPreviewModeChangeListener(mode -> {
             binding.pdfToolBar.selectMode(mode);
             screenStatusManager.changeWindowStatus(mode);
-            if (mode == CPreviewMode.Viewer) {
-                binding.pdfView.setViewMode(CPDFReaderView.ViewMode.VIEW);
-                binding.pdfView.changeFormType(CPDFWidget.WidgetType.Widget_Unknown);
-            } else {
-                binding.pdfView.setViewMode(CPDFReaderView.ViewMode.FORM);
-                binding.pdfView.changeFormType(CPDFWidget.WidgetType.Widget_SignatureFields);
-            }
+            binding.pdfView.setViewMode(CPDFReaderView.ViewMode.VIEW);
+            binding.pdfView.changeFormType(CPDFWidget.WidgetType.Widget_Unknown);
+            binding.signatureToolBar.reset();
             resetContextMenu(binding.pdfView, mode);
         });
         binding.pdfToolBar.setSearchBtnClickListener(v -> {
@@ -149,8 +144,8 @@ public class PDFSignaturesSampleActivity extends CBasicActivity {
                 sharePDF(binding.pdfView);
             });
             menuWindow.addItem(R.drawable.tools_ic_new_file, R.string.tools_open_document, v1 -> {
-                if (hasStoragePermissions(STORAGE_PERMISSIONS)) {
-                    selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+                if (CPermissionUtil.hasStoragePermissions(this)) {
+                    selectDocument();
                 } else {
                     requestStoragePermissions();
                 }
@@ -165,9 +160,17 @@ public class PDFSignaturesSampleActivity extends CBasicActivity {
 
     private void requestStoragePermissions(){
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){
-            startActivity(new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION));
+            CPermissionUtil.openManageAllFileAppSettings(this);
         }else {
-            EasyPermissions.requestPermissions(this, "request permission", REQUEST_EXTERNAL_PERMISSION, STORAGE_PERMISSIONS);
+            multiplePermissionResultLauncher.launch(STORAGE_PERMISSIONS, result -> {
+                if (CPermissionUtil.hasStoragePermissions(this)) {
+                    selectDocument();
+                }else {
+                    if (!CPermissionUtil.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)){
+                        showPermissionsRequiredDialog();
+                    }
+                }
+            });
         }
     }
 
@@ -200,17 +203,18 @@ public class PDFSignaturesSampleActivity extends CBasicActivity {
         });
     }
 
+
+    /**
+     *
+     */
     private void verifyDocumentSignStatus(){
-        int status = CertificateDigitalDatas.verifyDocumentSignStatus(binding.pdfView.getCPdfReaderView().getPDFDocument());
-        if (status == 0){
-            binding.signStatusView.setStatus(CVerifySignStatusView.Status.VALID);
-        }else if (status == 1){
-            binding.signStatusView.setStatus(CVerifySignStatusView.Status.FAILURES);
-        }else {
-            binding.signStatusView.setStatus(CVerifySignStatusView.Status.WRONG);
+        CPDFDocument document = binding.pdfView.getCPdfReaderView().getPDFDocument();
+        if (CertificateDigitalDatas.hasDigitalSignature(document)){
+            SignatureStatus status = CertificateDigitalDatas.verifyDocumentSignStatus(document);
+            binding.signStatusView.setStatus(status);
+            screenStatusManager.manager.bindTopToolView(binding.signStatusView);
+            screenStatusManager.constraintShow(binding.signStatusView);
         }
-        screenStatusManager.manager.bindTopToolView(binding.signStatusView);
-        screenStatusManager.constraintShow(binding.signStatusView);
     }
 
     private void registerSignaturesHelper(CPDFViewCtrl pdfView) {
@@ -218,13 +222,30 @@ public class PDFSignaturesSampleActivity extends CBasicActivity {
                 .registImpl(CPDFSignatureWidget.class, CDigitalSignatureWidgetImpl.class);
     }
 
-    @Override
-    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
-        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
-        if (requestCode == REQUEST_EXTERNAL_PERMISSION) {
-            if (EasyPermissions.hasPermissions(this, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
-                selectDocumentLauncher.launch(CFileUtils.getContentIntent());
-            }
+    private void selectDocument() {
+        if (binding.pdfView.getCPdfReaderView().getPDFDocument() == null){
+            selectDocumentLauncher.launch(null);
+            return;
+        }
+        if (!binding.pdfView.getCPdfReaderView().getPDFDocument().hasChanges()) {
+            selectDocumentLauncher.launch(null);
+            return;
         }
+        CAlertDialog alertDialog = CAlertDialog.newInstance(getString(com.compdfkit.tools.R.string.tools_save_title), getString(com.compdfkit.tools.R.string.tools_save_message));
+        alertDialog.setConfirmClickListener(v -> {
+            //save pdf document
+            binding.pdfView.savePDF((filePath, pdfUri) -> {
+                alertDialog.dismiss();
+                selectDocumentLauncher.launch(null);
+            }, e -> {
+                alertDialog.dismiss();
+                selectDocumentLauncher.launch(null);
+            });
+        });
+        alertDialog.setCancelClickListener(v -> {
+            alertDialog.dismiss();
+            selectDocumentLauncher.launch(null);
+        });
+        alertDialog.show(getSupportFragmentManager(), "alertDialog");
     }
 }

+ 1 - 1
DigitalSignature/src/main/res/values-night/themes.xml

@@ -1,4 +1,4 @@
-<resources xmlns:tools="http://schemas.android.com/tools">
+<resources>
     <!-- Base application theme. -->
     <style name="Theme.Compdfkit_android_demo" parent="Theme.MaterialComponents.DayNight.NoActionBar">
         <item name="android:statusBarColor">@color/tools_color_primary</item>

+ 2 - 2
DigitalSignature/src/test/java/com/compdfkit/digitalsignature/ExampleUnitTest.java

@@ -1,9 +1,9 @@
 package com.compdfkit.digitalsignature;
 
-import org.junit.Test;
-
 import static org.junit.Assert.*;
 
+import org.junit.Test;
+
 /**
  * Example local unit test, which will execute on the development machine (host).
  *

+ 0 - 1
DocsEditor/build.gradle

@@ -51,7 +51,6 @@ dependencies {
     implementation 'androidx.appcompat:appcompat:1.6.1'
     implementation 'com.google.android.material:material:1.8.0'
     implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
-    implementation 'pub.devrel:easypermissions:3.0.0'
     implementation project(':ComPDFKit_Tools')
 
 }

+ 22 - 27
DocsEditor/src/main/java/com/compdfkit/docseditor/MainActivity.java

@@ -5,16 +5,16 @@ import android.content.Intent;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.view.View;
 
 import androidx.activity.result.ActivityResultLauncher;
 import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
 
 import com.compdfkit.docseditor.databinding.ActivityMainBinding;
-import com.compdfkit.tools.common.activity.CBasicActivity;
+import com.compdfkit.tools.common.basic.activity.CBasicPDFActivity;
 import com.compdfkit.tools.common.utils.CFileUtils;
+import com.compdfkit.tools.common.utils.CPermissionUtil;
+import com.compdfkit.tools.common.utils.activitycontracts.CSelectPDFDocumentResultContract;
 import com.compdfkit.tools.common.utils.dialog.CAlertDialog;
 import com.compdfkit.tools.common.utils.task.CExtractAssetFileTask;
 import com.compdfkit.tools.common.utils.window.CPopupMenuWindow;
@@ -28,9 +28,7 @@ import com.compdfkit.ui.reader.CPDFReaderView;
 
 import java.util.ArrayList;
 
-import pub.devrel.easypermissions.EasyPermissions;
-
-public class MainActivity extends CBasicActivity {
+public class MainActivity extends CBasicPDFActivity {
 
     /**
      * assets folder pdf file
@@ -39,9 +37,8 @@ public class MainActivity extends CBasicActivity {
     ActivityMainBinding binding;
     CPageEditSampleScreenManager screenManager = new CPageEditSampleScreenManager();
 
-    private ActivityResultLauncher<Intent> selectDocumentLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
-        if (result.getData() != null && result.getData().getData() != null) {
-            Uri uri = result.getData().getData();
+    private ActivityResultLauncher<Void> selectDocumentLauncher = registerForActivityResult(new CSelectPDFDocumentResultContract(), uri -> {
+        if (uri != null) {
             CFileUtils.takeUriPermission(this, uri);
             binding.pdfView.openPDF(uri);
             binding.pdfToolBar.selectMode(CPreviewMode.Viewer);
@@ -135,7 +132,7 @@ public class MainActivity extends CBasicActivity {
                 sharePDF(binding.pdfView);
             });
             menuWindow.addItem(R.drawable.tools_ic_new_file, R.string.tools_open_document, v1 -> {
-                if (hasStoragePermissions(STORAGE_PERMISSIONS)) {
+                if (CPermissionUtil.hasStoragePermissions(this)) {
                     selectDocument();
                 } else {
                     requestStoragePermissions();
@@ -151,9 +148,17 @@ public class MainActivity extends CBasicActivity {
 
     private void requestStoragePermissions(){
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){
-            startActivity(new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION));
+            CPermissionUtil.openManageAllFileAppSettings(this);
         }else {
-            EasyPermissions.requestPermissions(this, "request permission", REQUEST_EXTERNAL_PERMISSION, STORAGE_PERMISSIONS);
+            multiplePermissionResultLauncher.launch(STORAGE_PERMISSIONS, result -> {
+                if (CPermissionUtil.hasStoragePermissions(this)) {
+                    selectDocument();
+                }else {
+                    if (!CPermissionUtil.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)){
+                        showPermissionsRequiredDialog();
+                    }
+                }
+            });
         }
     }
 
@@ -178,11 +183,11 @@ public class MainActivity extends CBasicActivity {
 
     private void selectDocument() {
         if (binding.pdfView.getCPdfReaderView().getPDFDocument() == null){
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+            selectDocumentLauncher.launch(null);
             return;
         }
         if (!binding.pdfView.getCPdfReaderView().getPDFDocument().hasChanges()){
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+            selectDocumentLauncher.launch(null);
             return;
         }
         CAlertDialog alertDialog = CAlertDialog.newInstance(getString(com.compdfkit.tools.R.string.tools_save_title), getString(com.compdfkit.tools.R.string.tools_save_message));
@@ -190,29 +195,19 @@ public class MainActivity extends CBasicActivity {
             //save pdf document
             binding.pdfView.savePDF((filePath, pdfUri) -> {
                 alertDialog.dismiss();
-                selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+                selectDocumentLauncher.launch(null);
             },e -> {
                 alertDialog.dismiss();
-                selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+                selectDocumentLauncher.launch(null);
             });
         });
         alertDialog.setCancelClickListener(v -> {
             alertDialog.dismiss();
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+            selectDocumentLauncher.launch(null);
         });
         alertDialog.show(getSupportFragmentManager(), "alertDialog");
     }
 
-    @Override
-    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
-        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
-        if (requestCode == REQUEST_EXTERNAL_PERMISSION) {
-            if (EasyPermissions.hasPermissions(this, android.Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
-                selectDocument();
-            }
-        }
-    }
-
     @Override
     public void onBackPressed() {
         if (binding.pdfView != null) {

+ 0 - 1
Forms/build.gradle

@@ -53,6 +53,5 @@ dependencies {
     implementation 'com.google.android.material:material:1.8.0'
     implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
     implementation project(':ComPDFKit_Tools')
-    implementation 'pub.devrel:easypermissions:3.0.0'
 
 }

+ 23 - 26
Forms/src/main/java/com/compdfkit/forms/PDFFormSampleActivity.java

@@ -1,11 +1,11 @@
 package com.compdfkit.forms;
 
+import android.Manifest;
 import android.content.Intent;
 import android.graphics.Paint;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.view.View;
 
 import androidx.activity.result.ActivityResultLauncher;
@@ -14,8 +14,10 @@ import androidx.annotation.NonNull;
 import androidx.core.content.ContextCompat;
 
 import com.compdfkit.forms.databinding.FormPdfSampleActivityBinding;
-import com.compdfkit.tools.common.activity.CBasicActivity;
+import com.compdfkit.tools.common.basic.activity.CBasicPDFActivity;
 import com.compdfkit.tools.common.utils.CFileUtils;
+import com.compdfkit.tools.common.utils.CPermissionUtil;
+import com.compdfkit.tools.common.utils.activitycontracts.CSelectPDFDocumentResultContract;
 import com.compdfkit.tools.common.utils.annotation.CPDFAnnotationManager;
 import com.compdfkit.tools.common.utils.dialog.CAlertDialog;
 import com.compdfkit.tools.common.utils.task.CExtractAssetFileTask;
@@ -32,9 +34,7 @@ import com.compdfkit.ui.reader.CPDFReaderView;
 
 import java.util.ArrayList;
 
-import pub.devrel.easypermissions.EasyPermissions;
-
-public class PDFFormSampleActivity extends CBasicActivity {
+public class PDFFormSampleActivity extends CBasicPDFActivity {
 
     /**
      * assets folder pdf file
@@ -45,9 +45,8 @@ public class PDFFormSampleActivity extends CBasicActivity {
 
     CFormSampleScreenManager screenManager = new CFormSampleScreenManager();
 
-    private ActivityResultLauncher<Intent> selectDocumentLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
-        if (result.getData() != null && result.getData().getData() != null) {
-            Uri uri = result.getData().getData();
+    private ActivityResultLauncher<Void> selectDocumentLauncher = registerForActivityResult(new CSelectPDFDocumentResultContract(), uri -> {
+        if (uri != null) {
             CFileUtils.takeUriPermission(this, uri);
             binding.pdfView.resetFormType();
             binding.formToolBar.reset();
@@ -162,7 +161,7 @@ public class PDFFormSampleActivity extends CBasicActivity {
                 sharePDF(binding.pdfView);
             });
             menuWindow.addItem(R.drawable.tools_ic_new_file, R.string.tools_open_document, v1 -> {
-                if (hasStoragePermissions(STORAGE_PERMISSIONS)) {
+                if (CPermissionUtil.hasStoragePermissions(this)) {
                     selectDocument();
                 } else {
                     requestStoragePermissions();
@@ -175,9 +174,17 @@ public class PDFFormSampleActivity extends CBasicActivity {
 
     private void requestStoragePermissions(){
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){
-            startActivity(new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION));
+            CPermissionUtil.openManageAllFileAppSettings(this);
         }else {
-            EasyPermissions.requestPermissions(this, "request permission", REQUEST_EXTERNAL_PERMISSION, STORAGE_PERMISSIONS);
+            multiplePermissionResultLauncher.launch(STORAGE_PERMISSIONS, result -> {
+                if (CPermissionUtil.hasStoragePermissions(this)) {
+                    selectDocument();
+                }else {
+                    if (!CPermissionUtil.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)){
+                        showPermissionsRequiredDialog();
+                    }
+                }
+            });
         }
     }
 
@@ -206,11 +213,11 @@ public class PDFFormSampleActivity extends CBasicActivity {
 
     private void selectDocument() {
         if (binding.pdfView.getCPdfReaderView().getPDFDocument() == null){
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+            selectDocumentLauncher.launch(null);
             return;
         }
         if (!binding.pdfView.getCPdfReaderView().getPDFDocument().hasChanges()) {
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+            selectDocumentLauncher.launch(null);
             return;
         }
         CAlertDialog alertDialog = CAlertDialog.newInstance(getString(com.compdfkit.tools.R.string.tools_save_title), getString(com.compdfkit.tools.R.string.tools_save_message));
@@ -218,29 +225,19 @@ public class PDFFormSampleActivity extends CBasicActivity {
             //save pdf document
             binding.pdfView.savePDF((filePath, pdfUri) -> {
                 alertDialog.dismiss();
-                selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+                selectDocumentLauncher.launch(null);
             }, e -> {
                 alertDialog.dismiss();
-                selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+                selectDocumentLauncher.launch(null);
             });
         });
         alertDialog.setCancelClickListener(v -> {
             alertDialog.dismiss();
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+            selectDocumentLauncher.launch(null);
         });
         alertDialog.show(getSupportFragmentManager(), "alertDialog");
     }
 
-    @Override
-    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
-        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
-        if (requestCode == REQUEST_EXTERNAL_PERMISSION) {
-            if (EasyPermissions.hasPermissions(this, STORAGE_PERMISSIONS)) {
-                selectDocument();
-            }
-        }
-    }
-
     @Override
     protected void onSaveInstanceState(@NonNull Bundle outState) {
         binding.pdfView.savePDF(null,e -> {});

+ 0 - 1
PDFViewer/build.gradle

@@ -51,6 +51,5 @@ dependencies {
     implementation 'androidx.appcompat:appcompat:1.6.1'
     implementation 'com.google.android.material:material:1.8.0'
     implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
-    implementation 'pub.devrel:easypermissions:3.0.0'
     api project(path: ':ComPDFKit_Tools')
 }

+ 36 - 54
PDFViewer/src/main/java/com/compdfkit/pdfviewer/MainActivity.java

@@ -18,21 +18,21 @@ import android.content.Intent;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.view.View;
 import android.widget.Toast;
 
 import androidx.activity.result.ActivityResultLauncher;
 import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.compdfkit.core.annotation.CPDFAnnotation;
 import com.compdfkit.core.edit.CPDFEditManager;
 import com.compdfkit.pdfviewer.databinding.PdfSampleActivityBinding;
-import com.compdfkit.tools.common.activity.CBasicActivity;
+import com.compdfkit.tools.common.basic.activity.CBasicPDFActivity;
 import com.compdfkit.tools.common.contextmenu.CPDFContextMenuHelper;
 import com.compdfkit.tools.common.utils.CFileUtils;
+import com.compdfkit.tools.common.utils.CPermissionUtil;
+import com.compdfkit.tools.common.utils.activitycontracts.CSelectPDFDocumentResultContract;
 import com.compdfkit.tools.common.utils.annotation.CPDFAnnotationManager;
 import com.compdfkit.tools.common.utils.dialog.CAlertDialog;
 import com.compdfkit.tools.common.utils.task.CExtractAssetFileTask;
@@ -56,13 +56,9 @@ import com.compdfkit.ui.reader.CPDFPageView;
 import com.compdfkit.ui.reader.CPDFReaderView;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 
-import pub.devrel.easypermissions.AfterPermissionGranted;
-import pub.devrel.easypermissions.AppSettingsDialog;
-import pub.devrel.easypermissions.EasyPermissions;
 
-public class MainActivity extends CBasicActivity {
+public class MainActivity extends CBasicPDFActivity {
 
     /**
      * assets folder pdf file
@@ -73,8 +69,8 @@ public class MainActivity extends CBasicActivity {
 
     CSampleScreenManager screenManager = new CSampleScreenManager();
 
-    private ActivityResultLauncher<Intent> selectDocumentLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
-        if (result.getData() != null && result.getData().getData() != null) {
+    private ActivityResultLauncher<Void> selectDocumentLauncher = registerForActivityResult(new CSelectPDFDocumentResultContract(), uri -> {
+        if (uri != null) {
             CPDFReaderView readerView = binding.pdfView.getCPdfReaderView();
             if (readerView != null && readerView.getEditManager() != null) {
                 readerView.getEditManager().endEdit();
@@ -82,7 +78,6 @@ public class MainActivity extends CBasicActivity {
             if (readerView.getContextMenuShowListener() != null) {
                 readerView.getContextMenuShowListener().dismissContextMenu();
             }
-            Uri uri = result.getData().getData();
             CFileUtils.takeUriPermission(this, uri);
             resetContextMenu(binding.pdfView, CPreviewMode.Viewer);
             binding.pdfView.resetAnnotationType();
@@ -97,8 +92,6 @@ public class MainActivity extends CBasicActivity {
         }
     });
 
-    private final static int RC_PERMISSION_PERM = 111;
-
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -179,8 +172,8 @@ public class MainActivity extends CBasicActivity {
                 editManager.enable();
                 editManager.beginEdit(CPDFEditPage.LoadTextImage);
             }
-            if (!hasStoragePermissions(STORAGE_PERMISSIONS)) {
-                EasyPermissions.requestPermissions(this, "request permission", 1234, STORAGE_PERMISSIONS);
+            if (!CPermissionUtil.hasStoragePermissions(this)) {
+                requestStoragePermissions();
             }
         } else {
 
@@ -274,7 +267,7 @@ public class MainActivity extends CBasicActivity {
                 sharePDF(binding.pdfView);
             });
             menuWindow.addItem(R.drawable.tools_ic_new_file, R.string.tools_open_document, v1 -> {
-                if (hasStoragePermissions(STORAGE_PERMISSIONS)) {
+                if (CPermissionUtil.hasStoragePermissions(this)) {
                     selectDocument();
                 } else {
                     requestStoragePermissions();
@@ -287,9 +280,17 @@ public class MainActivity extends CBasicActivity {
 
     private void requestStoragePermissions() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
-            startActivity(new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION));
+            CPermissionUtil.openManageAllFileAppSettings(this);
         } else {
-            EasyPermissions.requestPermissions(this, "request permission", REQUEST_EXTERNAL_PERMISSION, STORAGE_PERMISSIONS);
+            multiplePermissionResultLauncher.launch(STORAGE_PERMISSIONS, result -> {
+                if (CPermissionUtil.hasStoragePermissions(this)) {
+                    selectDocument();
+                }else {
+                    if (!CPermissionUtil.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)){
+                        showPermissionsRequiredDialog();
+                    }
+                }
+            });
         }
     }
 
@@ -300,8 +301,15 @@ public class MainActivity extends CBasicActivity {
             screenManager.changeWindowStatus(type);
             //You are required to grant recording permission when selecting voice notes
             if (type == CAnnotationType.SOUND) {
-                if (!EasyPermissions.hasPermissions(this, Manifest.permission.RECORD_AUDIO)) {
-                    EasyPermissions.requestPermissions(this, getString(R.string.tools_use_sound_annot), 112, Manifest.permission.RECORD_AUDIO);
+                if (!hasPermission(Manifest.permission.RECORD_AUDIO)) {
+                    permissionResultLauncher.launch(Manifest.permission.RECORD_AUDIO, hasRecordAudioPermission -> {
+                        if (!hasRecordAudioPermission){
+                            binding.pdfView.resetAnnotationType();
+                            if (!CPermissionUtil.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)){
+                                showPermissionsRequiredDialog();
+                            }
+                        }
+                    });
                 }
             }
         });
@@ -338,29 +346,6 @@ public class MainActivity extends CBasicActivity {
         });
     }
 
-    @Override
-    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
-        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
-        if (requestCode == REQUEST_EXTERNAL_PERMISSION) {
-            if (hasStoragePermissions(STORAGE_PERMISSIONS)) {
-                selectDocument();
-            }
-        } else if (requestCode == 112) {
-            if (!EasyPermissions.hasPermissions(this, permissions)) {
-                if (EasyPermissions.somePermissionPermanentlyDenied(this, Arrays.asList(permissions))) {
-                    new AppSettingsDialog.Builder(this)
-                            .build().show();
-                } else {
-                    binding.pdfView.resetAnnotationType();
-                }
-            }
-        } else if (requestCode == AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE) {
-            if (!EasyPermissions.hasPermissions(this, permissions)) {
-                binding.pdfView.resetAnnotationType();
-            }
-        }
-    }
-
     private void initEditBar() {
         if (binding.pdfView == null || binding.pdfView.getCPdfReaderView() == null) {
             return;
@@ -399,12 +384,12 @@ public class MainActivity extends CBasicActivity {
             binding.pdfView.exitEditMode();
         }
 
-        if (binding.pdfView.getCPdfReaderView().getPDFDocument() == null){
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+        if (binding.pdfView.getCPdfReaderView().getPDFDocument() == null) {
+            selectDocumentLauncher.launch(null);
             return;
         }
         if (!binding.pdfView.getCPdfReaderView().getPDFDocument().hasChanges()) {
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+            selectDocumentLauncher.launch(null);
             return;
         }
         CAlertDialog alertDialog = CAlertDialog.newInstance(getString(R.string.tools_save_title), getString(R.string.tools_save_message));
@@ -412,24 +397,21 @@ public class MainActivity extends CBasicActivity {
             //save pdf document
             binding.pdfView.savePDF((filePath, pdfUri) -> {
                 alertDialog.dismiss();
-                selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+                selectDocumentLauncher.launch(null);
             }, e -> {
                 alertDialog.dismiss();
-                selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+                selectDocumentLauncher.launch(null);
             });
         });
         alertDialog.setCancelClickListener(v -> {
             alertDialog.dismiss();
-            selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+            selectDocumentLauncher.launch(null);
         });
         alertDialog.show(getSupportFragmentManager(), "alertDialog");
     }
 
-    @AfterPermissionGranted(RC_PERMISSION_PERM)
     private void onDoNext() {
-        if (!hasStoragePermissions()) {
-            EasyPermissions.requestPermissions(this, getString(R.string.app_permission_storage), RC_PERMISSION_PERM, STORAGE_PERMISSIONS);
-        }
+        multiplePermissionResultLauncher.launch(STORAGE_PERMISSIONS);
     }
 
     @Override
@@ -483,7 +465,7 @@ public class MainActivity extends CBasicActivity {
     public void onBackPressed() {
         if (binding.pdfView != null) {
             binding.pdfView.savePDF((filePath, pdfUri) -> super.onBackPressed(), e -> super.onBackPressed());
-        }else {
+        } else {
             super.onBackPressed();
         }
     }

+ 0 - 1
Samples/src/main/java/com/compdfkit/samples/util/FileUtils.java

@@ -17,7 +17,6 @@ import android.os.Build;
 
 import androidx.core.content.FileProvider;
 
-
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;

+ 0 - 3
Viewer/build.gradle

@@ -52,7 +52,4 @@ dependencies {
     implementation 'com.google.android.material:material:1.8.0'
     implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
     implementation project(':ComPDFKit_Tools')
-
-
-    implementation 'pub.devrel:easypermissions:3.0.0'
 }

+ 14 - 24
Viewer/src/main/java/com/compdfkit/viewer/PDFViewerSampleActivity.java

@@ -9,22 +9,21 @@
 
 package com.compdfkit.viewer;
 
-import android.Manifest;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.view.View;
 
 import androidx.activity.result.ActivityResultLauncher;
 import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
 
 import com.compdfkit.core.annotation.CPDFTextAnnotation;
 import com.compdfkit.tools.annotation.pdfproperties.pdfnote.CPDFtextAnnotImpl;
-import com.compdfkit.tools.common.activity.CBasicActivity;
+import com.compdfkit.tools.common.basic.activity.CBasicPDFActivity;
 import com.compdfkit.tools.common.utils.CFileUtils;
+import com.compdfkit.tools.common.utils.CPermissionUtil;
+import com.compdfkit.tools.common.utils.activitycontracts.CSelectPDFDocumentResultContract;
 import com.compdfkit.tools.common.utils.task.CExtractAssetFileTask;
 import com.compdfkit.tools.common.utils.window.CPopupMenuWindow;
 import com.compdfkit.tools.common.views.pdfbota.CPDFBOTA;
@@ -37,9 +36,7 @@ import com.compdfkit.viewer.databinding.ViewerPdfSampleActivityBinding;
 
 import java.util.ArrayList;
 
-import pub.devrel.easypermissions.EasyPermissions;
-
-public class PDFViewerSampleActivity extends CBasicActivity {
+public class PDFViewerSampleActivity extends CBasicPDFActivity {
 
     /**
      * assets folder pdf file
@@ -50,9 +47,8 @@ public class PDFViewerSampleActivity extends CBasicActivity {
 
     private CViewerScreenStatusManager screenStatusManager;
 
-    private ActivityResultLauncher<Intent> selectDocumentLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
-        if (result.getData() != null && result.getData().getData() != null) {
-            Uri uri = result.getData().getData();
+    private ActivityResultLauncher<Void> selectDocumentLauncher = registerForActivityResult(new CSelectPDFDocumentResultContract(), uri -> {
+        if (uri != null) {
             CFileUtils.takeUriPermission(this, uri);
             binding.pdfView.openPDF(uri);
         }
@@ -125,8 +121,8 @@ public class PDFViewerSampleActivity extends CBasicActivity {
                 sharePDF(binding.pdfView);
             });
             menuWindow.addItem(R.drawable.tools_ic_new_file, R.string.tools_open_document, v1 -> {
-                if (hasStoragePermissions(STORAGE_PERMISSIONS)) {
-                    selectDocumentLauncher.launch(CFileUtils.getContentIntent());
+                if (CPermissionUtil.hasStoragePermissions(this)) {
+                    selectDocumentLauncher.launch(null);
                 } else {
                     requestStoragePermissions();
                 }
@@ -138,9 +134,13 @@ public class PDFViewerSampleActivity extends CBasicActivity {
 
     private void requestStoragePermissions(){
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){
-            startActivity(new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION));
+            CPermissionUtil.openManageAllFileAppSettings(this);
         }else {
-            EasyPermissions.requestPermissions(this, "request permission", REQUEST_EXTERNAL_PERMISSION, STORAGE_PERMISSIONS);
+            multiplePermissionResultLauncher.launch(STORAGE_PERMISSIONS, result -> {
+                if (CPermissionUtil.hasStoragePermissions(this)) {
+                    selectDocumentLauncher.launch(null);
+                }
+            });
         }
     }
 
@@ -163,14 +163,4 @@ public class PDFViewerSampleActivity extends CBasicActivity {
             binding.pdfSearchToolBar.showKeyboard();
         });
     }
-
-    @Override
-    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
-        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
-        if (requestCode == REQUEST_EXTERNAL_PERMISSION) {
-            if (EasyPermissions.hasPermissions(this, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
-                selectDocumentLauncher.launch(CFileUtils.getContentIntent());
-            }
-        }
-    }
 }