Browse Source

PDFTool(Android) - 注释列表新增菜单功能、注释回复交互

liuxiaolong 8 months ago
parent
commit
f36337076f
57 changed files with 1060 additions and 55 deletions
  1. BIN
      ComPDFKit_Repo/compdfkit-ui/ComPDFKit-UI.aar
  2. BIN
      ComPDFKit_Repo/compdfkit/ComPDFKit.aar
  3. 4 4
      ComPDFKit_Tools/build.gradle
  4. 3 1
      ComPDFKit_Tools/src/main/assets/tools_default_configuration.json
  5. 1 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/annotation/pdfannotationbar/data/CAnnotationToolDatas.java
  6. 196 7
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/annotation/pdfannotationlist/CPDFAnnotationListFragment.java
  7. 74 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/annotation/pdfannotationlist/adapter/CPDFAnnotListAdapter.java
  8. 20 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/annotation/pdfannotationlist/bean/CPDFAnnotListItem.java
  9. 53 2
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/annotation/pdfannotationlist/data/CPDFAnnotDatas.java
  10. 73 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/annotation/pdfannotationlist/dialog/CMarkedTipsWindow.java
  11. 3 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/basic/fragment/CBasicPDFFragment.java
  12. 3 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/CPDFConfigurationUtils.java
  13. 2 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/CPDFDocumentActivity.java
  14. 19 5
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/CPDFDocumentFragment.java
  15. 10 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/config/GlobalConfig.java
  16. 2 2
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/CFileUtils.java
  17. 23 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/CUriUtil.java
  18. 6 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/adapter/CBaseQuickAdapter.java
  19. 35 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/viewutils/CDimensUtils.java
  20. 9 9
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/window/CBasePopupWindow.java
  21. 51 0
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/views/pdfbota/CPDFBotaDialogFragment.java
  22. 12 3
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/views/pdfview/CPDFViewCtrl.java
  23. 1 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/docseditor/pdfpageedit/CPDFPageEditDialogFragment.java
  24. 7 2
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/security/encryption/CDocumentEncryptionDialog.java
  25. 7 1
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/security/watermark/CWatermarkEditDialog.java
  26. 5 2
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/CertificateDigitalDatas.java
  27. 1 2
      ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/signlist/CPDFCertDigitalSignListDialog.java
  28. 15 0
      ComPDFKit_Tools/src/main/res/anim/tools_popup_enter.xml
  29. 15 0
      ComPDFKit_Tools/src/main/res/anim/tools_popup_exit.xml
  30. 5 0
      ComPDFKit_Tools/src/main/res/drawable/tools_annot_marked_tips_bg.xml
  31. 5 0
      ComPDFKit_Tools/src/main/res/drawable/tools_annot_replies_checkbox_btn.xml
  32. 13 0
      ComPDFKit_Tools/src/main/res/drawable/tools_annot_review_status_accepted.xml
  33. 10 0
      ComPDFKit_Tools/src/main/res/drawable/tools_annot_review_status_cancelled.xml
  34. 10 0
      ComPDFKit_Tools/src/main/res/drawable/tools_annot_review_status_completed.xml
  35. 10 0
      ComPDFKit_Tools/src/main/res/drawable/tools_annot_review_status_none.xml
  36. 13 0
      ComPDFKit_Tools/src/main/res/drawable/tools_annot_review_status_rejected.xml
  37. 11 0
      ComPDFKit_Tools/src/main/res/drawable/tools_ic_btn_replies_checkbox_disable.xml
  38. 10 0
      ComPDFKit_Tools/src/main/res/drawable/tools_ic_btn_replies_checkbox_enable.xml
  39. 10 0
      ComPDFKit_Tools/src/main/res/drawable/tools_ic_up_arrow.xml
  40. 34 0
      ComPDFKit_Tools/src/main/res/layout/tools_annot_marked_tips.xml
  41. 59 9
      ComPDFKit_Tools/src/main/res/layout/tools_bota_annotation_list_item_content.xml
  42. 20 2
      ComPDFKit_Tools/src/main/res/layout/tools_bota_dialog_fragment.xml
  43. 20 0
      ComPDFKit_Tools/src/main/res/menu/tools_bota_dialog_annotation_list_menu.xml
  44. 20 1
      ComPDFKit_Tools/src/main/res/values/tools_strings.xml
  45. 5 0
      ComPDFKit_Tools/src/main/res/values/tools_styles.xml
  46. 31 0
      PDFViewer/src/debug/AndroidManifest.xml
  47. 4 0
      PDFViewer/src/main/java/com/compdfkit/pdfviewer/home/SettingActivity.java
  48. 1 0
      PDFViewer/src/main/java/com/compdfkit/pdfviewer/home/datas/FunDatas.java
  49. 10 0
      PDFViewer/src/main/java/com/compdfkit/pdfviewer/home/datas/SettingDatas.java
  50. 2 0
      PDFViewer/src/main/java/com/compdfkit/pdfviewer/home/samples/DocumentEncryptionSamplesImpl.java
  51. 2 0
      PDFViewer/src/main/java/com/compdfkit/pdfviewer/home/samples/WatermarkSamplesImpl.java
  52. 15 0
      PDFViewer/src/main/res/layout/activity_setting.xml
  53. 3 0
      PDFViewer/src/main/res/values-zh-rCN/strings.xml
  54. 1 0
      PDFViewer/src/main/res/values/strings.xml
  55. 2 0
      Samples/src/main/java/com/compdfkit/samples/SampleApplication.java
  56. 81 0
      Samples/src/main/java/com/compdfkit/samples/samples/AnnotationReplyTest.java
  57. 3 0
      Samples/src/main/res/values/strings.xml

BIN
ComPDFKit_Repo/compdfkit-ui/ComPDFKit-UI.aar


BIN
ComPDFKit_Repo/compdfkit/ComPDFKit.aar


+ 4 - 4
ComPDFKit_Tools/build.gradle

@@ -43,10 +43,10 @@ android {
 dependencies {
 
     api fileTree(include: ['*.jar'], dir: 'libs')
-//    api project(path:':ComPDFKit_Repo:compdfkit')
-//    api project(path:':ComPDFKit_Repo:compdfkit-ui')
-    api ('com.compdf:compdfkit:2.0.1')
-    api ('com.compdf:compdfkit-ui:2.0.1')
+    api project(path:':ComPDFKit_Repo:compdfkit')
+    api project(path:':ComPDFKit_Repo:compdfkit-ui')
+//    api ('com.compdf:compdfkit:2.0.1')
+//    api ('com.compdf:compdfkit-ui:2.0.1')
     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'

+ 3 - 1
ComPDFKit_Tools/src/main/assets/tools_default_configuration.json

@@ -257,6 +257,8 @@
     "pageSameWidth": true
   },
   "global" : {
-    "themeMode" : "system"
+    "themeMode" : "system",
+    "fileSaveExtraFontSubset" : true,
+    "annotationAuthor": "Guest"
   }
 }

+ 1 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/annotation/pdfannotationbar/data/CAnnotationToolDatas.java

@@ -9,6 +9,7 @@ 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;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -54,5 +55,4 @@ public class CAnnotationToolDatas {
         return list;
     }
 
-
 }

+ 196 - 7
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/annotation/pdfannotationlist/CPDFAnnotationListFragment.java

@@ -9,27 +9,53 @@
 
 package com.compdfkit.tools.annotation.pdfannotationlist;
 
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
 import android.os.Bundle;
+import android.os.Environment;
+import android.text.TextUtils;
+import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.PopupWindow;
 import android.widget.ProgressBar;
 
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.core.view.GravityCompat;
 import androidx.fragment.app.Fragment;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
+import com.compdfkit.core.annotation.CPDFAnnotation;
+import com.compdfkit.core.document.CPDFDocument;
+import com.compdfkit.core.page.CPDFPage;
 import com.compdfkit.tools.R;
+import com.compdfkit.tools.annotation.pdfannotationbar.data.CAnnotationToolDatas;
 import com.compdfkit.tools.annotation.pdfannotationlist.adapter.CPDFAnnotListAdapter;
 import com.compdfkit.tools.annotation.pdfannotationlist.bean.CPDFAnnotListItem;
 import com.compdfkit.tools.annotation.pdfannotationlist.data.CPDFAnnotDatas;
+import com.compdfkit.tools.annotation.pdfannotationlist.dialog.CMarkedTipsWindow;
 import com.compdfkit.tools.common.interfaces.COnSetPDFDisplayPageIndexListener;
+import com.compdfkit.tools.common.utils.CFileUtils;
+import com.compdfkit.tools.common.utils.CLog;
+import com.compdfkit.tools.common.utils.CToastUtil;
+import com.compdfkit.tools.common.utils.CUriUtil;
 import com.compdfkit.tools.common.utils.threadpools.CThreadPoolUtils;
+import com.compdfkit.tools.common.utils.viewutils.CDimensUtils;
+import com.compdfkit.tools.common.utils.window.CPopupMenuWindow;
+import com.compdfkit.tools.common.views.directory.CFileDirectoryDialog;
 import com.compdfkit.tools.common.views.pdfview.CPDFViewCtrl;
+import com.compdfkit.ui.reader.CPDFPageView;
 
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 
@@ -45,11 +71,42 @@ public class CPDFAnnotationListFragment extends Fragment {
     private CPDFAnnotListAdapter listAdapter;
 
     private ProgressBar progressBar;
+    private CPopupMenuWindow reviewStatusMenuWindow;
 
     public static CPDFAnnotationListFragment newInstance() {
         return new CPDFAnnotationListFragment();
     }
 
+
+    private ActivityResultLauncher<Intent> importAnnotFileLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
+        if (result.getResultCode() == Activity.RESULT_OK) {
+            Uri uri = result.getData().getData();
+            // get xfdf format file name
+            String fileName = CUriUtil.getUriFileName(getContext(), uri);
+            //Determine whether the file is in xfdf format
+            if (fileName.toLowerCase().endsWith(".xfdf")){
+                // Save the file to the app's internal storage cache directory
+                String dir = new File(getContext().getCacheDir(), CFileUtils.CACHE_FOLDER + File.separator + "xfdfFile").getAbsolutePath();
+                // Get the saved file path
+                String importFilePath = CFileUtils.copyFileToInternalDirectory(getContext(), uri, dir, fileName);
+                CLog.e("ComPDFKit-Tools", "importFilePath:" + importFilePath);
+
+                if (!TextUtils.isEmpty(importFilePath)){
+                    boolean importResult = CPDFAnnotDatas.importAnnotations(pdfView.getCPdfReaderView().getPDFDocument(), importFilePath);
+                    if (importResult){
+                        CToastUtil.showLongToast(getContext(), R.string.tools_import_success);
+                        updateAnnotationList();
+                        pdfView.getCPdfReaderView().reloadPages();
+                    }
+                    CLog.e("ComPDFKit-Tools", "import Annotation xfdf format file " + (importResult ? "success" : "fail"));
+                }
+            } else {
+                CLog.e("ComPDFKit-Tools", "Please select xfdf format file");
+                CToastUtil.showLongToast(getContext(), R.string.tools_please_select_xfdf_format_file);
+            }
+        }
+    });
+
     public void initWithPDFView(CPDFViewCtrl pdfView) {
         this.pdfView = pdfView;
     }
@@ -69,27 +126,44 @@ public class CPDFAnnotationListFragment extends Fragment {
         super.onViewCreated(view, savedInstanceState);
         listAdapter = new CPDFAnnotListAdapter();
         updateAnnotationList();
-        listAdapter.addOnItemChildClickListener(R.id.cl_root, (adapter, view1, position) -> {
+        listAdapter.addOnItemChildClickListener((adapter,view1,position) -> {
             CPDFAnnotListItem item = adapter.list.get(position);
-            if (!item.isHeader()) {
-                if (displayPageIndexListener != null) {
-                    displayPageIndexListener.displayPage(item.getPage());
+            if (view1.getId() == R.id.cl_root) {
+                if (!item.isHeader()) {
+                    if (displayPageIndexListener != null) {
+                        displayPageIndexListener.displayPage(item.getPage());
+                    }
                 }
+            } else if(view1.getId() == R.id.iv_review_status){
+                showReviewStatusMenu(item,position, view1);
+            } else if(view1.getId() == R.id.cb_marked_status){
+                showMarkedStatusMenu(position, view1);
+            } else if(view1.getId() == R.id.iv_more){
+                showAnnotationMoreMenu(item, position, view1);
             }
-        });
+        },R.id.iv_review_status, R.id.cb_marked_status, R.id.iv_more, R.id.cl_root);
+
         rvAnnotation.setLayoutManager(new LinearLayoutManager(getContext()));
         rvAnnotation.setAdapter(listAdapter);
     }
 
 
-    private void updateAnnotationList() {
-        progressBar.setVisibility(View.VISIBLE);
+    public void updateAnnotationList() {
+        updateAnnotationList(true);
+    }
+
+    public void updateAnnotationList(boolean showProgressBar) {
+        if (showProgressBar){
+            progressBar.setVisibility(View.VISIBLE);
+        }
         CThreadPoolUtils.getInstance().executeIO(() -> {
             List<CPDFAnnotListItem> list = CPDFAnnotDatas.getAnnotationList(pdfView);
             if (getActivity() != null) {
                 getActivity().runOnUiThread(()->{
                     if (list == null || list.size() <= 0) {
                         clEmptyView.setVisibility(View.VISIBLE);
+                    }else {
+                        clEmptyView.setVisibility(View.GONE);
                     }
                     listAdapter.setList(list);
                     progressBar.setVisibility(View.GONE);
@@ -98,6 +172,121 @@ public class CPDFAnnotationListFragment extends Fragment {
         });
     }
 
+
+    /**
+     * show toolbar annotation menu, in CPDFBOTAFragment
+     * @param anchorView
+     */
+    public void showAnnotationMenu(View anchorView){
+        CPopupMenuWindow menuWindow = new CPopupMenuWindow(getContext());
+        menuWindow.addItem(R.string.tools_import_annotations, v -> {
+            importAnnotFileLauncher.launch(CFileUtils.getIntent("application/octet-stream"));
+        });
+        menuWindow.addItem(R.string.tools_export_annotations, v -> {
+            String dirPath = Environment.getExternalStorageDirectory().getAbsolutePath();
+            CFileDirectoryDialog directoryDialog = CFileDirectoryDialog.newInstance(dirPath, getString(R.string.tools_saving_path), getString(R.string.tools_okay));
+            directoryDialog.setSelectFolderListener(dir -> {
+                CPDFDocument document = pdfView.getCPdfReaderView().getPDFDocument();
+                boolean result = CPDFAnnotDatas.exportAnnotations(document, dir, CFileUtils.getFileNameNoExtension(document.getFileName()));
+                if (result){
+                    CToastUtil.showLongToast(getContext(), R.string.tools_export_success);
+                }
+            });
+            directoryDialog.show(getChildFragmentManager(), "dirDialog");
+        });
+        menuWindow.addItem(R.string.tools_delete_all_annotations, v -> {
+            deleteAllAnnotations();
+        });
+        menuWindow.addItem(R.string.tools_delete_all_replies, v -> {
+            CPDFDocument document = pdfView.getCPdfReaderView().getPDFDocument();
+            CPDFAnnotDatas.removeAllAnnotationReply(document);
+            updateAnnotationList();
+        });
+        menuWindow.showAsDropDown(anchorView);
+    }
+
+    /**
+     * delete pdf document all annotations
+     */
+    public void deleteAllAnnotations(){
+        CPDFDocument document = pdfView.getCPdfReaderView().getPDFDocument();
+        boolean result = document.removeAllAnnotations();
+        if (result){
+            pdfView.getCPdfReaderView().reloadPages();
+            updateAnnotationList();
+        }
+    }
+
+    private void showReviewStatusMenu(CPDFAnnotListItem item,int position, View anchorView){
+        anchorView.setSelected(true);
+        reviewStatusMenuWindow = new CPopupMenuWindow(getContext());
+        reviewStatusMenuWindow.setOutsideTouchable(false);
+        reviewStatusMenuWindow.addItem(R.drawable.tools_annot_review_status_accepted, R.string.tools_accepted, v -> {
+            listAdapter.setReviewStatus(position, CPDFAnnotation.ReviewState.REVIEW_ACCEPTED);
+        });
+        reviewStatusMenuWindow.addItem(R.drawable.tools_annot_review_status_rejected, R.string.tools_rejected, v -> {
+            listAdapter.setReviewStatus(position, CPDFAnnotation.ReviewState.REVIEW_REJECTED);
+        });
+        reviewStatusMenuWindow.addItem(R.drawable.tools_annot_review_status_cancelled, R.string.tools_cancelled, v -> {
+            listAdapter.setReviewStatus(position, CPDFAnnotation.ReviewState.REVIEW_CANCELLED);
+
+        });
+        reviewStatusMenuWindow.addItem(R.drawable.tools_annot_review_status_completed, R.string.tools_completed, v -> {
+            listAdapter.setReviewStatus(position, CPDFAnnotation.ReviewState.REVIEW_COMPLETED);
+        });
+        reviewStatusMenuWindow.addItem(R.drawable.tools_annot_review_status_none, R.string.tools_none, v -> {
+            listAdapter.setReviewStatus(position, CPDFAnnotation.ReviewState.REVIEW_NONE);
+        });
+        reviewStatusMenuWindow.setOnDismissListener(() -> anchorView.setSelected(false));
+        int[] windowPos = CDimensUtils.calculatePopWindowPos(anchorView, reviewStatusMenuWindow.getContentView());
+        windowPos[0] -= reviewStatusMenuWindow.getContentView().getMeasuredWidth() /2;
+
+        windowPos[1] -= anchorView.getMeasuredHeight() / 2;
+        windowPos[1] -= anchorView.getMeasuredHeight();
+        reviewStatusMenuWindow.setAnimationStyle(R.style.PopupAnimation);
+        reviewStatusMenuWindow.showAtLocation(anchorView, Gravity.START | Gravity.TOP, windowPos[0], windowPos[1]);
+    }
+
+    private void showMarkedStatusMenu( int position,View anchorView){
+        listAdapter.checkedMarkedStatus(position);
+        CMarkedTipsWindow tipsWindow = new CMarkedTipsWindow(getContext());
+        tipsWindow.setMarkState(listAdapter.list.get(position).getMarkState());
+
+        tipsWindow.getContentView().measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+        int winWidth = tipsWindow.getContentView().getMeasuredWidth();
+        int winHeight = tipsWindow.getContentView().getMeasuredHeight();
+        int anchorViewWidth = anchorView.getWidth();
+        int anchorViewHeight = anchorView.getHeight();
+        int offsetX = (anchorViewWidth - winWidth) / 2;
+        int offsetY = anchorViewHeight + winHeight;
+        tipsWindow.showAsDropDown(anchorView, offsetX, -offsetY);
+    }
+
+    private void showAnnotationMoreMenu(CPDFAnnotListItem item, int position, View anchorView){
+        CPopupMenuWindow moreMenu = new CPopupMenuWindow(getContext());
+        moreMenu.addItem(R.string.tools_add_a_new_reply,v -> {
+
+        });
+        moreMenu.addItem(R.string.tools_view_replies, v -> {
+
+        });
+        moreMenu.addItem(R.string.tools_delete_annotation, v -> {
+            boolean result = item.getAttr().removeFromPage();
+            if (result){
+                listAdapter.remove(position);
+                ArrayList<Integer> pages = new ArrayList<>();
+                pages.add(item.getPage());
+                pdfView.getCPdfReaderView().reloadPages(pages);
+                pdfView.getCPdfReaderView().postDelayed(()-> updateAnnotationList(false), 450);
+            }
+        });
+        int[] windowPos = CDimensUtils.calculatePopWindowPos(anchorView, moreMenu.getContentView());
+        windowPos[0] -= anchorView.getMeasuredWidth() /2 ;
+        windowPos[1] -= anchorView.getMeasuredHeight();
+        moreMenu.setAnimationStyle(R.style.PopupAnimation);
+        moreMenu.showAtLocation(anchorView, Gravity.START | Gravity.TOP, windowPos[0], windowPos[1]);
+    }
+
     public void setPDFDisplayPageIndexListener(COnSetPDFDisplayPageIndexListener displayPageIndexListener) {
         this.displayPageIndexListener = displayPageIndexListener;
     }

+ 74 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/annotation/pdfannotationlist/adapter/CPDFAnnotListAdapter.java

@@ -15,10 +15,15 @@ import android.graphics.Color;
 import android.text.TextUtils;
 import android.view.ViewGroup;
 
+import androidx.annotation.NonNull;
+import androidx.cardview.widget.CardView;
 import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.RecyclerView;
 
 import com.compdfkit.core.annotation.CPDFAnnotation;
+import com.compdfkit.core.annotation.CPDFReplyAnnotation;
 import com.compdfkit.tools.R;
+import com.compdfkit.tools.annotation.pdfannotationbar.bean.CAnnotToolBean;
 import com.compdfkit.tools.annotation.pdfannotationlist.bean.CPDFAnnotListItem;
 import com.compdfkit.tools.common.utils.adapter.CBaseQuickAdapter;
 import com.compdfkit.tools.common.utils.adapter.CBaseQuickViewHolder;
@@ -26,10 +31,15 @@ import com.compdfkit.tools.common.utils.viewutils.CViewUtils;
 import com.google.android.material.color.MaterialColors;
 
 import java.util.HashMap;
+import java.util.List;
 
 
 public class CPDFAnnotListAdapter  extends CBaseQuickAdapter<CPDFAnnotListItem, CBaseQuickViewHolder> {
 
+    private static final String REFRESH_MARKED_STATUS = "refresh_marked_status";
+
+    public static final String REFRESH_REVIEW_STATUS = "refresh_review_status";
+
     private static final int ITEM_HEADER = 1;
 
     private static final int ITEM_CONTENT = 2;
@@ -137,8 +147,72 @@ public class CPDFAnnotListAdapter  extends CBaseQuickAdapter<CPDFAnnotListItem,
             holder.setVisible(R.id.tv_annot_content, !TextUtils.isEmpty(item.getContent()));
             holder.setText(R.id.tv_annot_content, item.getContent());
             holder.setText(R.id.tv_annot_date, item.getModifyDate());
+            holder.setText(R.id.tv_author, item.getAttr().getTitle());
+            refreshReviewStatus(holder, item, item.getReviewState());
+            refreshMarkedStatus(holder, item.getMarkState());
+        }
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
+        if (payloads.isEmpty()){
+            super.onBindViewHolder(holder, position, payloads);
+        }else {
+            for (Object payload : payloads) {
+                if(payload == REFRESH_REVIEW_STATUS){
+                    refreshReviewStatus((CBaseQuickViewHolder) holder, list.get(holder.getAdapterPosition()), list.get(holder.getAdapterPosition()).getReviewState());
+                } else if(payload == REFRESH_MARKED_STATUS){
+                    refreshMarkedStatus((CBaseQuickViewHolder) holder, list.get(holder.getAdapterPosition()).getMarkState());
+                }
+            }
         }
+    }
 
+    private void refreshReviewStatus(CBaseQuickViewHolder adapter, CPDFAnnotListItem item, CPDFAnnotation.ReviewState reviewState){
+//        CPDFReplyAnnotation replyAnnotation =
+        switch (reviewState){
+            case REVIEW_NONE:
+                adapter.setImageResource(R.id.iv_review_status, R.drawable.tools_annot_review_status_none);
+                break;
+            case REVIEW_ACCEPTED:
+                adapter.setImageResource(R.id.iv_review_status, R.drawable.tools_annot_review_status_accepted);
+
+                break;
+            case REVIEW_REJECTED:
+                adapter.setImageResource(R.id.iv_review_status, R.drawable.tools_annot_review_status_rejected);
+
+                break;
+            case REVIEW_COMPLETED:
+                adapter.setImageResource(R.id.iv_review_status, R.drawable.tools_annot_review_status_completed);
+
+                break;
+            case REVIEW_CANCELLED:
+                adapter.setImageResource(R.id.iv_review_status, R.drawable.tools_annot_review_status_cancelled);
+                break;
+            case REVIEW_ERROR:
+                adapter.setImageResource(R.id.iv_review_status, R.drawable.tools_annot_review_status_none);
+                break;
+            default:break;
+        }
+    }
+
+    private void refreshMarkedStatus(CBaseQuickViewHolder adapter, CPDFAnnotation.MarkState markState){
+        adapter.setChecked(R.id.cb_marked_status, markState == CPDFAnnotation.MarkState.MARKED);
+    }
+
+    public void setReviewStatus(int position, CPDFAnnotation.ReviewState reviewState){
+        list.get(position).setReviewState(reviewState);
+        notifyItemChanged(position, REFRESH_REVIEW_STATUS);
+    }
+
+    public void checkedMarkedStatus(int position){
+        CPDFAnnotListItem item = list.get(position);
+        if (item.getMarkState() == CPDFAnnotation.MarkState.MARKED) {
+            item.setMarkState(CPDFAnnotation.MarkState.UNMARKED);
+        }else {
+            item.setMarkState(CPDFAnnotation.MarkState.MARKED);
+        }
+        notifyItemChanged(position, REFRESH_MARKED_STATUS);
     }
 
     @Override

+ 20 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/annotation/pdfannotationlist/bean/CPDFAnnotListItem.java

@@ -34,6 +34,26 @@ public class CPDFAnnotListItem {
 
     private CPDFAnnotation attr;
 
+    private CPDFAnnotation.ReviewState reviewState = CPDFAnnotation.ReviewState.REVIEW_NONE;
+
+    private CPDFAnnotation.MarkState markState = CPDFAnnotation.MarkState.UNMARKED;
+
+    public CPDFAnnotation.ReviewState getReviewState() {
+        return reviewState;
+    }
+
+    public void setReviewState(CPDFAnnotation.ReviewState reviewState) {
+        this.reviewState = reviewState;
+    }
+
+    public CPDFAnnotation.MarkState getMarkState() {
+        return markState;
+    }
+
+    public void setMarkState(CPDFAnnotation.MarkState markState) {
+        this.markState = markState;
+    }
+
     public CPDFAnnotation.Type getAnnotType() {
         return annotType;
     }

+ 53 - 2
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/annotation/pdfannotationlist/data/CPDFAnnotDatas.java

@@ -11,6 +11,7 @@ import com.compdfkit.core.annotation.CPDFFreetextAnnotation;
 import com.compdfkit.core.annotation.CPDFHighlightAnnotation;
 import com.compdfkit.core.annotation.CPDFInkAnnotation;
 import com.compdfkit.core.annotation.CPDFLineAnnotation;
+import com.compdfkit.core.annotation.CPDFReplyAnnotation;
 import com.compdfkit.core.annotation.CPDFSoundAnnotation;
 import com.compdfkit.core.annotation.CPDFSquareAnnotation;
 import com.compdfkit.core.annotation.CPDFSquigglyAnnotation;
@@ -20,10 +21,14 @@ import com.compdfkit.core.annotation.CPDFTextAnnotation;
 import com.compdfkit.core.annotation.CPDFUnderlineAnnotation;
 import com.compdfkit.core.common.CPDFDate;
 import com.compdfkit.core.document.CPDFDocument;
+import com.compdfkit.core.page.CPDFPage;
 import com.compdfkit.tools.annotation.pdfannotationlist.bean.CPDFAnnotListItem;
+import com.compdfkit.tools.common.utils.CFileUtils;
+import com.compdfkit.tools.common.utils.CLog;
 import com.compdfkit.tools.common.utils.date.CDateUtil;
 import com.compdfkit.tools.common.views.pdfview.CPDFViewCtrl;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -69,8 +74,9 @@ public class CPDFAnnotDatas {
             boolean isArrowLine = true;
             int attrColor = Color.TRANSPARENT;
             String attrTime = "";
-            if (null != cpdfAnnotation.getCreationDate()){
-                attrTime = CPDFDate.toStandardDate(cpdfAnnotation.getCreationDate());
+            CPDFDate modifyDate = cpdfAnnotation.getRecentlyModifyDate();
+            if (null != modifyDate){
+                attrTime = CPDFDate.toStandardDate(modifyDate);
             }
             int attrAlpha = 0;
             String attrContent = "";
@@ -166,4 +172,49 @@ public class CPDFAnnotDatas {
         }
         return annotListItems;
     }
+
+
+    /**
+     * export annotations to xfdf file
+     * @param document
+     * @param saveDir Saved directory
+     * @param saveName The name of the saved file, excluding the xfdf file suffix
+     * @return export success or failure status
+     */
+    public static boolean exportAnnotations(CPDFDocument document, String saveDir, String saveName){
+        File dirFile = new File(saveDir);
+        File saveFile = new File(dirFile, saveName+".xfdf");
+        saveFile = CFileUtils.renameNameSuffix(saveFile);
+        if (dirFile.isDirectory() && !dirFile.exists()){
+            dirFile.mkdirs();
+        }
+        File cacheFile = new File(document.getContext().getCacheDir(), "annotationExportCache");
+        cacheFile.mkdirs();
+        CLog.e("ComPDFKit", "Annotation export path:" + saveFile.getAbsolutePath());
+        return document.exportAnnotations(saveFile.getAbsolutePath(), cacheFile.getAbsolutePath());
+    }
+
+    /**
+     * Import annotations in xfdf file
+     * @param document
+     * @param importFilePath imported xfdf file path
+     * @return
+     */
+    public static boolean importAnnotations(CPDFDocument document, String importFilePath){
+        File cacheFile = new File(document.getContext().getCacheDir(), "annotationExportCache");
+        cacheFile.mkdirs();
+        return document.importAnnotations(importFilePath, cacheFile.getAbsolutePath());
+    }
+
+    public static void removeAllAnnotationReply(CPDFDocument document){
+        for (int i = 0; i < document.getPageCount(); i++) {
+            CPDFPage page = document.pageAtIndex(i);
+            List<CPDFAnnotation> annotations = page.getAnnotations();
+            if (annotations != null) {
+                for (CPDFAnnotation annotation : annotations) {
+                    annotation.removeFromPageIncludeReplyAnnot();
+                }
+            }
+        }
+    }
 }

+ 73 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/annotation/pdfannotationlist/dialog/CMarkedTipsWindow.java

@@ -0,0 +1,73 @@
+/**
+ * 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.annotation.pdfannotationlist.dialog;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.appcompat.widget.AppCompatTextView;
+
+import com.compdfkit.core.annotation.CPDFAnnotation;
+import com.compdfkit.tools.R;
+import com.compdfkit.tools.common.utils.window.CBasePopupWindow;
+
+public class CMarkedTipsWindow extends CBasePopupWindow {
+
+  private CPDFAnnotation.MarkState markState = CPDFAnnotation.MarkState.MARKED;
+
+  private AppCompatTextView tvMarked;
+
+  public CMarkedTipsWindow(Context context) {
+    super(context);
+  }
+
+  @Override
+  protected View setLayout(LayoutInflater inflater) {
+    return LayoutInflater.from(mContext).inflate(R.layout.tools_annot_marked_tips, null);
+  }
+
+  @Override
+  protected void initResource() {}
+
+  @Override
+  protected void initListener() {}
+
+  @Override
+  protected void initView() {
+    tvMarked = mContentView.findViewById(R.id.tv_marked_status);
+  }
+
+  public void setMarkState(CPDFAnnotation.MarkState markState) {
+    this.markState = markState;
+    if (markState == CPDFAnnotation.MarkState.MARKED){
+      tvMarked.setText(R.string.tools_marked);
+    }else {
+      tvMarked.setText(R.string.tools_unmarked);
+    }
+  }
+
+  @Override
+  public View getContentView() {
+    return super.getContentView();
+  }
+
+  @Override
+  protected void onClickListener(View view) {}
+
+  @Override
+  public void showAsDropDown(View anchor, int xoff, int yoff) {
+    super.showAsDropDown(anchor, xoff, yoff);
+    try{
+      anchor.postDelayed(this::dismiss, 500);
+    }catch (Exception e){
+
+    }
+  }
+}

+ 3 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/basic/fragment/CBasicPDFFragment.java

@@ -29,6 +29,7 @@ import com.compdfkit.tools.common.contextmenu.impl.CEditImageContextMenuView;
 import com.compdfkit.tools.common.contextmenu.impl.CEditTextContextMenuView;
 import com.compdfkit.tools.common.contextmenu.impl.CSearchReplaceContextMenuView;
 import com.compdfkit.tools.common.contextmenu.impl.CSignatureContextMenuView;
+import com.compdfkit.tools.common.pdf.config.CPDFConfiguration;
 import com.compdfkit.tools.common.utils.CFileUtils;
 import com.compdfkit.tools.common.utils.dialog.CLoadingDialog;
 import com.compdfkit.tools.common.views.pdfview.CPDFViewCtrl;
@@ -45,6 +46,8 @@ import java.io.File;
 
 public class CBasicPDFFragment extends CPermissionFragment {
 
+    protected CPDFConfiguration cpdfConfiguration;
+
     public int curEditMode = CPDFEditPage.LoadNone;
 
     protected Uri documentUri;

+ 3 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/CPDFConfigurationUtils.java

@@ -702,6 +702,9 @@ public class CPDFConfigurationUtils {
     private static GlobalConfig parseGlobalConfig(@Nullable JSONObject jsonObject) {
         GlobalConfig globalConfig = new GlobalConfig();
         globalConfig.themeMode = GlobalConfig.CThemeMode.fromString(jsonObject.optString("themeMode", "light"));
+        globalConfig.fileSaveExtraFontSubset = jsonObject.optBoolean("fileSaveExtraFontSubset", true);
+        globalConfig.annotationAuthor = jsonObject.optString("annotationAuthor", "");
+
         return globalConfig;
     }
 }

+ 2 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/CPDFDocumentActivity.java

@@ -19,9 +19,10 @@ import androidx.annotation.Nullable;
 
 import com.compdfkit.tools.R;
 import com.compdfkit.tools.common.basic.activity.CBasicPDFActivity;
+import com.compdfkit.tools.common.basic.activity.CPermissionActivity;
 import com.compdfkit.tools.common.pdf.config.CPDFConfiguration;
 
-public class CPDFDocumentActivity extends CBasicPDFActivity {
+public class CPDFDocumentActivity extends CPermissionActivity {
 
     public static final String EXTRA_FILE_PATH = CPDFDocumentFragment.EXTRA_FILE_PATH;
     public static final String EXTRA_FILE_PASSWORD = CPDFDocumentFragment.EXTRA_FILE_PASSWORD;

+ 19 - 5
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/CPDFDocumentFragment.java

@@ -38,6 +38,7 @@ import androidx.constraintlayout.widget.ConstraintLayout;
 import androidx.core.content.ContextCompat;
 
 import com.compdfkit.core.annotation.CPDFAnnotation;
+import com.compdfkit.core.annotation.CPDFFreetextAnnotation;
 import com.compdfkit.core.annotation.form.CPDFSignatureWidget;
 import com.compdfkit.core.document.CPDFDocument;
 import com.compdfkit.core.edit.CPDFEditManager;
@@ -51,6 +52,7 @@ import com.compdfkit.tools.common.contextmenu.CPDFContextMenuHelper;
 import com.compdfkit.tools.common.pdf.config.CPDFConfiguration;
 import com.compdfkit.tools.common.pdf.config.ToolbarConfig;
 import com.compdfkit.tools.common.utils.CFileUtils;
+import com.compdfkit.tools.common.utils.CLog;
 import com.compdfkit.tools.common.utils.CPermissionUtil;
 import com.compdfkit.tools.common.utils.CToastUtil;
 import com.compdfkit.tools.common.utils.activitycontracts.CSelectPDFDocumentResultContract;
@@ -84,6 +86,7 @@ import com.compdfkit.tools.signature.info.signlist.CPDFCertDigitalSignListDialog
 import com.compdfkit.tools.signature.verify.CVerifySignStatusView;
 import com.compdfkit.tools.viewer.pdfsearch.CSearchReplaceToolbar;
 import com.compdfkit.ui.contextmenu.IContextMenuShowListener;
+import com.compdfkit.ui.proxy.CPDFAnnotDefaultImpl;
 import com.compdfkit.ui.proxy.form.CPDFComboboxWidgetImpl;
 import com.compdfkit.ui.proxy.form.CPDFListboxWidgetImpl;
 import com.compdfkit.ui.proxy.form.CPDFPushbuttonWidgetImpl;
@@ -106,8 +109,6 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
 
     protected CSampleScreenManager screenManager = new CSampleScreenManager();
 
-    protected CPDFConfiguration cpdfConfiguration;
-
     public ConstraintLayout clRoot;
 
     public CPDFViewCtrl pdfView;
@@ -135,6 +136,7 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
     private View blockView;
 
     private OnBackPressedCallback onBackPressedCallback;
+
     private CPopupMenuWindow menuWindow;
 
     public static CPDFDocumentFragment newInstance(String filePath, String password, CPDFConfiguration configuration) {
@@ -265,6 +267,7 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
         Paint paint = new Paint();
         paint.setStyle(Paint.Style.FILL);
         paint.setColor(ContextCompat.getColor(getContext(), R.color.tools_color_accent_50));
+        pdfView.setSaveFileExtraFontSubset(cpdfConfiguration.globalConfig.fileSaveExtraFontSubset);
         pdfView.getCPdfReaderView().setFormPreviewPaint(paint);
         pdfView.addOnPDFFocusedTypeChangeListener(type -> {
             if (type != CPDFAnnotation.Type.INK) {
@@ -284,6 +287,12 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
             }
         });
         pdfView.getCPdfReaderView().setPdfAddAnnotCallback((cpdfPageView, cpdfBaseAnnot) -> {
+            CLog.e("ComPDFKit","Add Annot Callback- type:" + cpdfBaseAnnot.getAnnotType().name());
+            CPDFAnnotation annotation = cpdfBaseAnnot.onGetAnnotation();
+            annotation.setTitle(cpdfConfiguration.globalConfig.annotationAuthor);
+            annotation.updateAp();
+
+            CLog.e("ComPDFKit","Add Annot Callback- setTitle:"+annotation.getTitle());
             // Annotation creation completed listener, you can use cpdfBaseAnnot.getAnnotType() to determine the type of the added annotation
             if (cpdfBaseAnnot instanceof CPDFListboxWidgetImpl) {
                 // When the ListBox form is created, display an editing dialog for adding list data
@@ -402,6 +411,9 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
                                 tabs.add(outlineTab);
                                 tabs.add(bookmarkTab);
                                 tabs.add(annotationTab);
+                                if (pdfToolBar.getMode() == CPreviewMode.Annotation){
+                                    annotationTab.setDefaultSelect(true);
+                                }
                             }
                             CPDFBotaDialogFragment dialogFragment = CPDFBotaDialogFragment.newInstance();
                             dialogFragment.initWithPDFView(pdfView);
@@ -580,6 +592,7 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
                         menuWindow.addItem(R.drawable.tools_ic_add_watermark, R.string.tools_watermark, v1 -> {
                             CWatermarkEditDialog watermarkEditDialog = CWatermarkEditDialog.newInstance();
                             watermarkEditDialog.setDocument(pdfView.getCPdfReaderView().getPDFDocument());
+                            watermarkEditDialog.setSaveFileExtraFontSubset(pdfView.isSaveFileExtraFontSubset());
                             watermarkEditDialog.setPageIndex(pdfView.currentPageIndex);
                             watermarkEditDialog.setCompleteListener((pdfFile) -> {
                                 pdfView.getCPdfReaderView().reloadPages();
@@ -598,8 +611,8 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
                         menuWindow.addItem(R.drawable.tools_ic_document_info, R.string.tools_document_info, v1 -> showDocumentInfo(pdfView));
                         break;
                     case Save:
-                        menuWindow.addItem(R.drawable.tools_ic_menu_save, R.string.tools_save, v1 -> pdfView.savePDF((filePath, pdfUri) -> CToastUtil.showLongToast(getContext(), R.string.tools_save_success), e -> {
-
+                        menuWindow.addItem(R.drawable.tools_ic_menu_save, R.string.tools_save, v1 ->
+                                pdfView.savePDF((filePath, pdfUri) -> CToastUtil.showLongToast(getContext(), R.string.tools_save_success), e -> {
                         }));
                         break;
                     case Share:
@@ -659,7 +672,7 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
                 boolean result = document.flattenAllPages(CPDFPage.PDFFlattenOption.FLAT_NORMALDISPLAY);
                 if (result) {
                     try {
-                        boolean saveResult = document.saveAs(finalFile.getAbsolutePath(), false);
+                        boolean saveResult = document.saveAs(finalFile.getAbsolutePath(), false, cpdfConfiguration.globalConfig.fileSaveExtraFontSubset);
                         CThreadPoolUtils.getInstance().executeMain(() -> {
                             dismissLoadingDialog();
                             if (document.shouleReloadDocument()) {
@@ -746,6 +759,7 @@ public class CPDFDocumentFragment extends CBasicPDFFragment {
     private void showSettingEncryptionDialog() {
         CDocumentEncryptionDialog documentEncryptionDialog = CDocumentEncryptionDialog.newInstance();
         documentEncryptionDialog.setDocument(pdfView.getCPdfReaderView().getPDFDocument());
+        documentEncryptionDialog.setSaveFileExtraFontSubset(pdfView.isSaveFileExtraFontSubset());
         documentEncryptionDialog.setEncryptionResultListener((isRemoveSecurity, result, filePath, passowrd) -> {
             pdfView.getCPdfReaderView().reloadPages();
             pdfView.openPDF(filePath);

+ 10 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/pdf/config/GlobalConfig.java

@@ -26,4 +26,14 @@ public class GlobalConfig  implements Serializable {
 
     public CThemeMode themeMode  = CThemeMode.Light;
 
+    /**
+     * Whether to save the used font set to the PDF file when saving the file.
+     * Saving to the file will increase the file size.
+     * Enabled by default
+     */
+    public boolean fileSaveExtraFontSubset = true;
+
+
+    public String annotationAuthor = "";
+
 }

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

@@ -120,7 +120,7 @@ public class CFileUtils {
 
     public static String copyFileToInternalDirectory(
             Context context,
-            Uri imageUri,
+            Uri uri,
             String dir,
             String fileName
     ) {
@@ -129,7 +129,7 @@ public class CFileUtils {
             file.getParentFile().mkdirs();
 
             ContentResolver cr = context.getContentResolver();
-            ParcelFileDescriptor fd = cr.openFileDescriptor(imageUri, "r");
+            ParcelFileDescriptor fd = cr.openFileDescriptor(uri, "r");
             FileInputStream ist = new FileInputStream(fd.getFileDescriptor());
             FileOutputStream outputStream = new FileOutputStream(file.getAbsolutePath());
             if (writeFile(ist, outputStream)) {

+ 23 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/CUriUtil.java

@@ -15,6 +15,29 @@ import java.io.InputStream;
 
 public class CUriUtil {
 
+    public static String getUriType(Context context, Uri uri) {
+
+        Cursor cursor = null;
+        final String column = MediaStore.Files.FileColumns.MIME_TYPE;
+        final String[] projection = {column};
+
+        try {
+            cursor = context.getContentResolver().query(uri, projection, null, null,
+                    null);
+            if (cursor != null && cursor.moveToFirst()) {
+                final int column_index = cursor.getColumnIndexOrThrow(column);
+                return cursor.getString(column_index);
+            }
+        } catch (Exception e) {
+
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+        return "";
+    }
+
     public static String getUriFileName(Context context, Uri uri) {
 
         Cursor cursor = null;

+ 6 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/adapter/CBaseQuickAdapter.java

@@ -190,6 +190,12 @@ public abstract class CBaseQuickAdapter<T,VH extends CBaseQuickViewHolder> exten
         childClickArray.put(viewId, listener);
     }
 
+    public void addOnItemChildClickListener(OnItemChildClickListener<T> listener, @IdRes int... viewIds){
+        for (int viewId : viewIds) {
+            childClickArray.put(viewId, listener);
+        }
+    }
+
     public void addOnItemChildLongClickListener(@IdRes int viewId, OnItemChildLongClickListener<T> listener){
         childLongClickArray.put(viewId, listener);
     }

+ 35 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/viewutils/CDimensUtils.java

@@ -11,6 +11,7 @@ package com.compdfkit.tools.common.utils.viewutils;
 
 import android.content.Context;
 import android.util.DisplayMetrics;
+import android.view.View;
 
 
 public class CDimensUtils {
@@ -50,4 +51,38 @@ public class CDimensUtils {
         int width = getScreenWidth(context);
         return Math.min(width, height);
     }
+
+    /**
+     * The calculated position aligns the y-direction with the top or bottom of the anchorView,
+     * and the x-direction aligns with the right side of the screen.
+     * If the position of the anchorView changes, you can add an appropriate offset to correct it.
+     * @param anchorView the view that triggers the window
+     * @param contentView the content layout of the window
+     * @return the xOff and yOff coordinates of the top-left corner where the window is displayed
+     */
+    public static int[] calculatePopWindowPos(final View anchorView, final View contentView) {
+        final int windowPos[] = new int[2];
+        final int anchorLoc[] = new int[2];
+        anchorView.getLocationOnScreen(anchorLoc);
+        final int anchorHeight = anchorView.getHeight();
+        // Get the screen height and width
+        final int screenHeight = getScreenHeight(anchorView.getContext());
+        final int screenWidth = getScreenWidth(anchorView.getContext());
+        contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+        // Calculate the height and width of the contentView
+        final int windowHeight = contentView.getMeasuredHeight();
+        final int windowWidth = contentView.getMeasuredWidth();
+        // Determine whether to pop up or down
+        final boolean isNeedShowUp = (screenHeight - anchorLoc[1] - anchorHeight < windowHeight);
+        if (isNeedShowUp) {
+            windowPos[0] = screenWidth - windowWidth;
+            windowPos[1] = anchorLoc[1] - windowHeight;
+        } else {
+            windowPos[0] = screenWidth - windowWidth;
+            windowPos[1] = anchorLoc[1] + anchorHeight;
+        }
+        return windowPos;
+    }
+
+
 }

+ 9 - 9
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/utils/window/CBasePopupWindow.java

@@ -35,15 +35,15 @@ public abstract class CBasePopupWindow extends PopupWindow implements View.OnCli
         setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
         setSoftInputMode(PopupWindow.INPUT_METHOD_NEEDED);
 //        setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
-        setFocusable(false);
-        setOutsideTouchable(true);
-        setTouchInterceptor((v, event) -> {
-            if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
-                dismiss();
-                return true;
-            }
-            return false;
-        });
+        setFocusable(true);
+//        setOutsideTouchable(true);
+//        setTouchInterceptor((v, event) -> {
+//            if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+//                dismiss();
+//                return false;
+//            }
+//            return false;
+//        });
 
         imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
 

+ 51 - 0
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/views/pdfbota/CPDFBotaDialogFragment.java

@@ -10,17 +10,37 @@
 package com.compdfkit.tools.common.views.pdfbota;
 
 
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
 import android.os.Bundle;
+import android.os.Environment;
+import android.text.TextUtils;
 import android.view.View;
 
+import androidx.activity.result.ActivityResultCallback;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.appcompat.widget.AppCompatImageView;
+import androidx.fragment.app.Fragment;
 import androidx.viewpager2.widget.ViewPager2;
 
+import com.compdfkit.core.document.CPDFDocument;
 import com.compdfkit.tools.R;
+import com.compdfkit.tools.annotation.pdfannotationbar.data.CAnnotationToolDatas;
+import com.compdfkit.tools.annotation.pdfannotationlist.CPDFAnnotationListFragment;
 import com.compdfkit.tools.common.basic.fragment.CBasicBottomSheetDialogFragment;
+import com.compdfkit.tools.common.utils.CFileUtils;
+import com.compdfkit.tools.common.utils.CLog;
+import com.compdfkit.tools.common.utils.CToastUtil;
+import com.compdfkit.tools.common.utils.CUriUtil;
+import com.compdfkit.tools.common.utils.threadpools.CThreadPoolUtils;
 import com.compdfkit.tools.common.utils.viewutils.CViewUtils;
+import com.compdfkit.tools.common.utils.window.CPopupMenuWindow;
 import com.compdfkit.tools.common.views.CToolBar;
+import com.compdfkit.tools.common.views.directory.CFileDirectoryDialog;
 import com.compdfkit.tools.common.views.pdfbota.adapter.CBotaViewPagerAdapter;
 import com.compdfkit.tools.common.views.pdfview.CPDFViewCtrl;
 import com.compdfkit.tools.viewer.pdfoutline.CPDFOutlineFragment;
@@ -28,7 +48,9 @@ import com.compdfkit.tools.viewer.pdfthumbnail.CPDFThumbnailFragment;
 import com.google.android.material.tabs.TabLayout;
 import com.google.android.material.tabs.TabLayoutMediator;
 
+import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 
 
 /**
@@ -46,6 +68,8 @@ public class CPDFBotaDialogFragment extends CBasicBottomSheetDialogFragment {
 
     private CPDFViewCtrl pdfView;
 
+    private AppCompatImageView ivMenu;
+
     private ArrayList<CPDFBotaFragmentTabs> tabs = new ArrayList<>();
 
     public static CPDFBotaDialogFragment newInstance(){
@@ -84,7 +108,14 @@ public class CPDFBotaDialogFragment extends CBasicBottomSheetDialogFragment {
         tabLayout = rootView.findViewById(R.id.tab_layout);
         viewPager2 = rootView.findViewById(R.id.view_pager);
         toolBar = rootView.findViewById(R.id.tool_bar);
+        ivMenu = rootView.findViewById(R.id.iv_menu);
         toolBar.setBackBtnClickListener(v -> dismiss());
+        ivMenu.setOnClickListener(v -> {
+            CPDFAnnotationListFragment annotationListFragment = getAnnotationFragment();
+            if (annotationListFragment != null){
+                annotationListFragment.showAnnotationMenu(ivMenu);
+            }
+        });
     }
 
     @Override
@@ -118,11 +149,13 @@ public class CPDFBotaDialogFragment extends CBasicBottomSheetDialogFragment {
         viewPager2.setCurrentItem(getDefaultSelectIndex(), false);
         if (tabs.size()>0){
             toolBar.setTitle(tabs.get(getDefaultSelectIndex()).getTitle());
+            ivMenu.setVisibility(tabs.get(getDefaultSelectIndex()).getBotaType() == CPDFBOTA.ANNOTATION ? View.VISIBLE : View.GONE);
         }
         viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
             @Override
             public void onPageSelected(int position) {
                 toolBar.setTitle(tabs.get(position).getTitle());
+                ivMenu.setVisibility(tabs.get(position).getBotaType() == CPDFBOTA.ANNOTATION ? View.VISIBLE : View.GONE);
             }
         });
         TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager2, (tab, position) -> {
@@ -145,9 +178,27 @@ public class CPDFBotaDialogFragment extends CBasicBottomSheetDialogFragment {
         return defaultSelectIndex;
     }
 
+
+    private @Nullable CPDFAnnotationListFragment getAnnotationFragment(){
+        int annotationIndex = 0;
+        for (int i = 0; i < tabs.size(); i++) {
+            if (tabs.get(i).getBotaType() == CPDFBOTA.ANNOTATION) {
+                annotationIndex = i;
+                break;
+            }
+        }
+        Fragment fragment = getChildFragmentManager().findFragmentByTag("f"+annotationIndex);
+        if (fragment != null && fragment instanceof CPDFAnnotationListFragment){
+           return (CPDFAnnotationListFragment) fragment;
+        }else {
+            return null;
+        }
+    }
+
     @Override
     public void onSaveInstanceState(@NonNull Bundle outState) {
         outState.putSerializable("tabs", tabs);
         super.onSaveInstanceState(outState);
     }
+
 }

+ 12 - 3
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/common/views/pdfview/CPDFViewCtrl.java

@@ -143,6 +143,7 @@ public class CPDFViewCtrl extends ConstraintLayout implements IReaderViewCallbac
 
     private List<OnFocusedTypeChangedListener> pdfViewFocusedListenerList = new ArrayList<>();
 
+    private boolean saveFileExtraFontSubset = false;
 
     private Runnable hideIndicatorRunnable = () -> {
         if (pageIndicatorAnimator != null) {
@@ -372,7 +373,7 @@ public class CPDFViewCtrl extends ConstraintLayout implements IReaderViewCallbac
         }
     }
 
-    public void savePDF(COnSaveCallback callback, COnSaveError error) {
+    public void savePDF(COnSaveCallback callback, COnSaveError error){
         CThreadPoolUtils.getInstance().executeMain(() -> {
             cPdfReaderView.pauseAllRenderProcess();
             cPdfReaderView.removeAllAnnotFocus();
@@ -389,9 +390,9 @@ public class CPDFViewCtrl extends ConstraintLayout implements IReaderViewCallbac
             exitEditMode();
             if (document.hasChanges()) {
                 try {
-                    boolean success = document.save();
+                    boolean success = document.save(CPDFDocument.PDFDocumentSaveType.PDFDocumentSaveIncremental, saveFileExtraFontSubset);
                     if (!success) {
-                        document.save(CPDFDocument.PDFDocumentSaveType.PDFDocumentSaveNoIncremental);
+                        document.save(CPDFDocument.PDFDocumentSaveType.PDFDocumentSaveNoIncremental, saveFileExtraFontSubset);
                     }
                     if (callback != null) {
                         callback.callback(document.getAbsolutePath(), document.getUri());
@@ -618,6 +619,14 @@ public class CPDFViewCtrl extends ConstraintLayout implements IReaderViewCallbac
         initCPDFSliderBar();
     }
 
+    public void setSaveFileExtraFontSubset(boolean saveFileExtraFontSubset) {
+        this.saveFileExtraFontSubset = saveFileExtraFontSubset;
+    }
+
+    public boolean isSaveFileExtraFontSubset() {
+        return saveFileExtraFontSubset;
+    }
+
     public interface OnTapMainDocAreaCallback {
         void onTapMainDocArea();
     }

+ 1 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/docseditor/pdfpageedit/CPDFPageEditDialogFragment.java

@@ -431,7 +431,7 @@ public class CPDFPageEditDialogFragment extends CBasicBottomSheetDialogFragment
         CPDFDocument newDocument = CPDFDocument.createDocument(getContext());
         res = newDocument.importPages(pdfView.getCPdfReaderView().getPDFDocument(), pageNum, 0);
         try {
-            res &= newDocument.saveAs(filePath, false);
+            res &= newDocument.saveAs(filePath, false, false, pdfView.isSaveFileExtraFontSubset());
         } catch (Exception e) {
 
         }

+ 7 - 2
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/security/encryption/CDocumentEncryptionDialog.java

@@ -106,6 +106,8 @@ public class CDocumentEncryptionDialog extends CBasicBottomSheetDialogFragment i
 
     private CPDFDocument document;
 
+    private boolean saveFileExtraFontSubset = false;
+
     private CEncryptionResultListener encryptionResultListener;
 
     protected CMultiplePermissionResultLauncher multiplePermissionResultLauncher = new CMultiplePermissionResultLauncher(this);
@@ -114,6 +116,9 @@ public class CDocumentEncryptionDialog extends CBasicBottomSheetDialogFragment i
         this.document = document;
     }
 
+    public void setSaveFileExtraFontSubset(boolean saveFileExtraFontSubset) {
+        this.saveFileExtraFontSubset = saveFileExtraFontSubset;
+    }
 
     @Override
     protected boolean fullScreen() {
@@ -393,10 +398,10 @@ public class CDocumentEncryptionDialog extends CBasicBottomSheetDialogFragment i
                 String filePath = CFileUtils.renameNameSuffix(file).getAbsolutePath();
                 if (isRemoveSecurity) {
                     // remove security
-                    result = document.saveAs(filePath, true);
+                    result = document.saveAs(filePath, true, false, saveFileExtraFontSubset);
                 } else {
                     // Save to specified directory
-                    result = document.saveAs(filePath, false);
+                    result = document.saveAs(filePath, false, false, saveFileExtraFontSubset);
                 }
                 boolean shouleReloadDocument = document.shouleReloadDocument();
                 CLog.e("ComPDFKit", "是否需要重新加载文档:" + shouleReloadDocument);

+ 7 - 1
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/security/watermark/CWatermarkEditDialog.java

@@ -81,6 +81,8 @@ public class CWatermarkEditDialog extends CBasicBottomSheetDialogFragment implem
 
     private String password;
 
+    private boolean saveFileExtraFontSubset = false;
+
     protected CMultiplePermissionResultLauncher multiplePermissionResultLauncher = new CMultiplePermissionResultLauncher(this);
 
     public static CWatermarkEditDialog newInstance() {
@@ -94,6 +96,10 @@ public class CWatermarkEditDialog extends CBasicBottomSheetDialogFragment implem
         this.document = document;
     }
 
+    public void setSaveFileExtraFontSubset(boolean saveFileExtraFontSubset) {
+        this.saveFileExtraFontSubset = saveFileExtraFontSubset;
+    }
+
     public void setDocument(@Nullable String pdfFilePath, @Nullable Uri uri) {
         this.pdfFilePath = pdfFilePath;
         this.pdfUri = uri;
@@ -239,7 +245,7 @@ public class CWatermarkEditDialog extends CBasicBottomSheetDialogFragment implem
                             if (!success) {
                                 return null;
                             }
-                            boolean result = document.saveAs(pdfFile.getAbsolutePath(), false);
+                            boolean result = document.saveAs(pdfFile.getAbsolutePath(), false, false, saveFileExtraFontSubset);
                             return result ? pdfFile.getAbsolutePath() : null;
                         } catch (Exception e) {
 

+ 5 - 2
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/CertificateDigitalDatas.java

@@ -22,6 +22,7 @@ import com.compdfkit.core.signature.CPDFSignature;
 import com.compdfkit.core.signature.CPDFSigner;
 import com.compdfkit.core.signature.CPDFX509;
 import com.compdfkit.tools.R;
+import com.compdfkit.tools.common.views.pdfview.CPDFViewCtrl;
 import com.compdfkit.tools.signature.bean.CPDFDocumentSignInfo;
 import com.compdfkit.tools.signature.bean.CPDFSignatureStatusInfo;
 import com.compdfkit.ui.reader.CPDFReaderView;
@@ -202,12 +203,14 @@ public class CertificateDigitalDatas {
         }
     }
 
-    public static boolean removeDigitalSign(CPDFReaderView readerView, CPDFDocument document, CPDFSignature signature) {
+    public static boolean removeDigitalSign(CPDFViewCtrl pdfView, CPDFSignature signature) {
         try {
+            CPDFReaderView readerView = pdfView.getCPdfReaderView();
+            CPDFDocument document = readerView.getPDFDocument();
             boolean result = document.removeSignature(signature, true, cpdfSignatureWidget ->{
                 readerView.refreshSignatureWidget(cpdfSignatureWidget);
             });
-            document.save();
+            document.save(CPDFDocument.PDFDocumentSaveType.PDFDocumentSaveIncremental, pdfView.isSaveFileExtraFontSubset());
             return result;
         } catch (Exception e) {
             e.printStackTrace();

+ 1 - 2
ComPDFKit_Tools/src/main/java/com/compdfkit/tools/signature/info/signlist/CPDFCertDigitalSignListDialog.java

@@ -105,8 +105,7 @@ public class CPDFCertDigitalSignListDialog extends CBasicBottomSheetDialogFragme
                 alertDialog.dismiss();
             });
             alertDialog.setConfirmClickListener(v -> {
-                boolean result = CertificateDigitalDatas.removeDigitalSign(pdfView.getCPdfReaderView(),
-                        pdfView.getCPdfReaderView().getPDFDocument(), signature.getSignature());
+                boolean result = CertificateDigitalDatas.removeDigitalSign(pdfView, signature.getSignature());
                 if (result) {
                     signListAdapter.remove(position);
                 }

+ 15 - 0
ComPDFKit_Tools/src/main/res/anim/tools_popup_enter.xml

@@ -0,0 +1,15 @@
+<!-- res/anim/popup_enter.xml -->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <alpha
+        android:duration="100"
+        android:fromAlpha="0.0"
+        android:toAlpha="1.0"/>
+    <scale
+        android:duration="100"
+        android:fromXScale="0.9"
+        android:fromYScale="0.9"
+        android:pivotX="50%"
+        android:pivotY="30%"
+        android:toXScale="1.0"
+        android:toYScale="1.0" />
+</set>

+ 15 - 0
ComPDFKit_Tools/src/main/res/anim/tools_popup_exit.xml

@@ -0,0 +1,15 @@
+<!-- res/anim/popup_exit.xml -->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <alpha
+        android:duration="100"
+        android:fromAlpha="1.0"
+        android:toAlpha="0.0"/>
+    <scale
+        android:duration="100"
+        android:fromXScale="1.0"
+        android:fromYScale="1.0"
+        android:pivotX="50%"
+        android:pivotY="30%"
+        android:toXScale="0.9"
+        android:toYScale="0.9" />
+</set>

+ 5 - 0
ComPDFKit_Tools/src/main/res/drawable/tools_annot_marked_tips_bg.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners android:radius="8dp"/>
+    <solid android:color="#E6616161"/>
+</shape>

+ 5 - 0
ComPDFKit_Tools/src/main/res/drawable/tools_annot_replies_checkbox_btn.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/tools_ic_btn_replies_checkbox_enable" android:state_checked="true"/>
+    <item android:drawable="@drawable/tools_ic_btn_replies_checkbox_disable" />
+</selector>

File diff suppressed because it is too large
+ 13 - 0
ComPDFKit_Tools/src/main/res/drawable/tools_annot_review_status_accepted.xml


+ 10 - 0
ComPDFKit_Tools/src/main/res/drawable/tools_annot_review_status_cancelled.xml

@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M5.9,5.5H18.9V18.5H5.9V5.5ZM4.4,4H5.9H18.9H20.4V5.5V18.5V20H18.9H5.9H4.4V18.5V5.5V4ZM9.561,8L10.092,8.53L12.502,10.94L14.912,8.53L15.442,8L16.503,9.061L15.972,9.591L13.562,12.001L15.972,14.411L16.503,14.942L15.442,16.002L14.912,15.472L12.502,13.062L10.092,15.472L9.561,16.002L8.5,14.942L9.031,14.411L11.441,12.001L9.031,9.591L8.5,9.061L9.561,8Z"
+      android:fillColor="#43474D"
+      android:fillType="evenOdd"/>
+</vector>

+ 10 - 0
ComPDFKit_Tools/src/main/res/drawable/tools_annot_review_status_completed.xml

@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M5.5,5.5H18.5V18.5H5.5V5.5ZM4,4H5.5H18.5H20V5.5V18.5V20H18.5H5.5H4V18.5V5.5V4ZM16.267,10.776L16.797,10.245L15.736,9.185L15.206,9.715L10.645,14.276L8.93,12.561L8.4,12.031L7.339,13.091L7.87,13.622L10.115,15.867L10.645,16.397L11.176,15.867L16.267,10.776Z"
+      android:fillColor="#43474D"
+      android:fillType="evenOdd"/>
+</vector>

+ 10 - 0
ComPDFKit_Tools/src/main/res/drawable/tools_annot_review_status_none.xml

@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M5.5,5.5H18.5V18.5H5.5V5.5ZM4,4H5.5H18.5H20V5.5V18.5V20H18.5H5.5H4V18.5V5.5V4ZM8.5,11.25H7.75V12.75H8.5H15.5H16.25V11.25H15.5H8.5Z"
+      android:fillColor="#43474D"
+      android:fillType="evenOdd"/>
+</vector>

File diff suppressed because it is too large
+ 13 - 0
ComPDFKit_Tools/src/main/res/drawable/tools_annot_review_status_rejected.xml


+ 11 - 0
ComPDFKit_Tools/src/main/res/drawable/tools_ic_btn_replies_checkbox_disable.xml

@@ -0,0 +1,11 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M5,3.75L19,3.75A1.25,1.25 0,0 1,20.25 5L20.25,19A1.25,1.25 0,0 1,19 20.25L5,20.25A1.25,1.25 0,0 1,3.75 19L3.75,5A1.25,1.25 0,0 1,5 3.75z"
+      android:strokeWidth="1.5"
+      android:fillColor="#00000000"
+      android:strokeColor="#CCCCCC"/>
+</vector>

+ 10 - 0
ComPDFKit_Tools/src/main/res/drawable/tools_ic_btn_replies_checkbox_enable.xml

@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M5,4.5H19C19.276,4.5 19.5,4.724 19.5,5V19C19.5,19.276 19.276,19.5 19,19.5H5C4.724,19.5 4.5,19.276 4.5,19V5C4.5,4.724 4.724,4.5 5,4.5ZM3,5C3,3.895 3.895,3 5,3H19C20.105,3 21,3.895 21,5V19C21,20.105 20.105,21 19,21H5C3.895,21 3,20.105 3,19V5ZM12,17.143C14.84,17.143 17.143,14.84 17.143,12C17.143,9.16 14.84,6.857 12,6.857C9.159,6.857 6.857,9.16 6.857,12C6.857,14.84 9.159,17.143 12,17.143Z"
+      android:fillColor="#999999"
+      android:fillType="evenOdd"/>
+</vector>

+ 10 - 0
ComPDFKit_Tools/src/main/res/drawable/tools_ic_up_arrow.xml

@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="13dp"
+    android:height="6dp"
+    android:viewportWidth="13"
+    android:viewportHeight="6">
+  <path
+      android:pathData="M6.5,0L12.5,6H0.5L6.5,0Z"
+      android:fillColor="#616161"
+      android:fillAlpha="0.9"/>
+</vector>

+ 34 - 0
ComPDFKit_Tools/src/main/res/layout/tools_annot_marked_tips.xml

@@ -0,0 +1,34 @@
+<?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"
+    android:layout_width="60dp"
+    android:layout_height="wrap_content">
+
+
+    <androidx.appcompat.widget.AppCompatTextView
+        android:id="@+id/tv_marked_status"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@drawable/tools_annot_marked_tips_bg"
+        android:gravity="center_horizontal"
+        android:maxWidth="80dp"
+        android:paddingHorizontal="8dp"
+        android:paddingVertical="8dp"
+        android:text="@string/tools_marked"
+        android:textColor="@android:color/white"
+        android:textSize="12sp"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <androidx.appcompat.widget.AppCompatImageView
+        android:id="@+id/iv_arrow"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:rotation="180"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/tv_marked_status"
+        app:srcCompat="@drawable/tools_ic_up_arrow" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 59 - 9
ComPDFKit_Tools/src/main/res/layout/tools_bota_annotation_list_item_content.xml

@@ -2,9 +2,9 @@
 <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:id="@+id/cl_root"
     android:background="@drawable/tools_common_btn_rectangle_ripple"
     android:paddingHorizontal="16dp"
     android:paddingVertical="12dp">
@@ -13,8 +13,9 @@
         android:id="@+id/fl_annot_icon"
         android:layout_width="24dp"
         android:layout_height="24dp"
+        app:layout_constraintBottom_toBottomOf="@id/tv_annot_date"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent">
+        app:layout_constraintTop_toTopOf="@id/tv_author">
 
         <View
             android:id="@+id/view_icon_bg"
@@ -30,34 +31,83 @@
 
     </FrameLayout>
 
-
     <androidx.appcompat.widget.AppCompatTextView
-        android:id="@+id/tv_annot_date"
+        android:id="@+id/tv_author"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginStart="8dp"
         android:textColor="?android:attr/textColorPrimary"
-        app:layout_constraintBottom_toBottomOf="@id/fl_annot_icon"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintBottom_toTopOf="@id/tv_annot_date"
+        app:layout_constraintEnd_toStartOf="@id/iv_review_status"
+        app:layout_constraintHorizontal_bias="0"
         app:layout_constraintStart_toEndOf="@id/fl_annot_icon"
-        app:layout_constraintTop_toTopOf="@id/fl_annot_icon"
+        app:layout_constraintTop_toTopOf="parent"
+        android:maxLines="1"
+        android:ellipsize="end"
+        tools:text="@tools:sample/full_names" />
+
+    <androidx.appcompat.widget.AppCompatTextView
+        android:id="@+id/tv_annot_date"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textColor="?android:attr/textColorSecondary"
+        android:textSize="11sp"
+        app:layout_constraintBottom_toBottomOf="@id/fl_annot_icon"
+        app:layout_constraintStart_toStartOf="@id/tv_author"
+        app:layout_constraintTop_toBottomOf="@id/tv_author"
         tools:text="@tools:sample/date/ddmmyy" />
 
+    <androidx.appcompat.widget.AppCompatImageView
+        android:id="@+id/iv_more"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        app:tint="?attr/colorOnPrimary"
+        android:background="@drawable/tools_common_btn_corner_ripple"
+        app:layout_constraintBottom_toBottomOf="@id/fl_annot_icon"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="@id/fl_annot_icon"
+        app:srcCompat="@drawable/tools_ic_more_vertical" />
+
+    <CheckBox
+        android:id="@+id/cb_marked_status"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_marginEnd="8dp"
+        android:buttonTint="?attr/colorOnPrimary"
+        android:button="@drawable/tools_annot_replies_checkbox_btn"
+        app:layout_constraintBottom_toBottomOf="@id/iv_more"
+        app:layout_constraintEnd_toStartOf="@id/iv_more"
+        tools:checked="false" />
+
+    <androidx.appcompat.widget.AppCompatImageView
+        android:id="@+id/iv_review_status"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_marginEnd="8dp"
+        app:tint="@color/tools_icon_status_color"
+        android:background="@drawable/tools_common_btn_corner_ripple"
+        app:layout_constraintBottom_toBottomOf="@id/iv_more"
+        app:layout_constraintEnd_toStartOf="@id/cb_marked_status"
+        app:srcCompat="@drawable/tools_annot_review_status_none" />
+
+
     <androidx.appcompat.widget.AppCompatTextView
         android:id="@+id/tv_annot_content"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_marginTop="4dp"
-        android:maxLines="2"
         android:ellipsize="end"
+        android:maxLines="2"
         android:textColor="?android:attr/textColorSecondary"
+        android:textSize="14sp"
         android:visibility="visible"
         app:layout_constrainedWidth="true"
-        android:textSize="14sp"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintHorizontal_bias="0"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/fl_annot_icon"
+        app:layout_constraintTop_toBottomOf="@id/tv_annot_date"
         tools:text="@tools:sample/lorem/random" />
 
 

+ 20 - 2
ComPDFKit_Tools/src/main/res/layout/tools_bota_dialog_fragment.xml

@@ -2,7 +2,8 @@
 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    xmlns:tools="http://schemas.android.com/tools">
 
     <com.compdfkit.tools.common.views.CToolBar
         android:id="@+id/tool_bar"
@@ -14,7 +15,24 @@
         app:layout_constraintTop_toTopOf="parent"
         app:tools_toolbar_back_icon="@drawable/tools_ic_back"
         android:title="@string/tools_outlines"
-         />
+        android:animateLayoutChanges="true"
+        >
+
+        <androidx.appcompat.widget.AppCompatImageView
+            android:id="@+id/iv_menu"
+            android:layout_width="35dp"
+            android:layout_height="35dp"
+            android:src="@drawable/tools_ic_more_vertical"
+            android:layout_gravity="center_vertical|end"
+            android:layout_marginEnd="16dp"
+            app:tint="?attr/colorOnPrimary"
+            android:visibility="gone"
+            tools:visibility="visible"
+            android:padding="4dp"
+            android:background="@drawable/tools_common_oval_ripple"
+            />
+
+    </com.compdfkit.tools.common.views.CToolBar>
 
     <com.google.android.material.tabs.TabLayout
         android:id="@+id/tab_layout"

+ 20 - 0
ComPDFKit_Tools/src/main/res/menu/tools_bota_dialog_annotation_list_menu.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:id="@+id/menu_import_annotations"
+        android:title="@string/tools_import_annotations"/>
+
+    <item
+        android:id="@+id/menu_export_annotations"
+        android:title="@string/tools_export_annotations"/>
+
+    <item
+        android:id="@+id/menu_delete_all_annotations"
+        android:title="@string/tools_delete_all_annotations"/>
+
+    <item
+        android:id="@+id/menu_delete_all_replies"
+        android:title="@string/tools_delete_all_replies"/>
+
+</menu>

+ 20 - 1
ComPDFKit_Tools/src/main/res/values/tools_strings.xml

@@ -494,5 +494,24 @@
     <string name="tools_font_style_bold">Bold</string>
     <string name="tools_font_style_italic">Italic</string>
     <string name="tools_font_style_bold_italic">Bold&amp;Italic</string>
-
+    
+    
+<!--    v2.1.0-->
+    <string name="tools_import_annotations">Import Annotations</string>
+    <string name="tools_export_annotations">Export Annotations</string>
+    <string name="tools_delete_all_annotations">Delete All Annotations</string>
+    <string name="tools_delete_all_replies">Delete All Replies</string>
+    <string name="tools_import_success">Import successful</string>
+    <string name="tools_please_select_xfdf_format_file">Please select xfdf format file</string>
+    
+    <string name="tools_accepted">Accepted</string>
+    <string name="tools_rejected">Rejected</string>
+    <string name="tools_cancelled">Cancelled</string>
+    <string name="tools_completed">Completed</string>
+
+    <string name="tools_marked">Marked</string>
+    <string name="tools_unmarked">UnMarked</string>
+    <string name="tools_add_a_new_reply">Add a new Reply</string>
+    <string name="tools_view_replies">View Replies</string>
+    <string name="tools_delete_annotation">Delete Annotation</string>
 </resources>

+ 5 - 0
ComPDFKit_Tools/src/main/res/values/tools_styles.xml

@@ -151,4 +151,9 @@
     <style name="ComPDFKit.Theme.BottomSheetStyle.Transparent"  tools:ignore="ResourceName">
         <item name="android:background">@android:color/transparent</item>
     </style>
+
+    <style name="PopupAnimation">
+        <item name="android:windowEnterAnimation">@anim/tools_popup_enter</item>
+        <item name="android:windowExitAnimation">@anim/tools_popup_exit</item>
+    </style>
 </resources>

+ 31 - 0
PDFViewer/src/debug/AndroidManifest.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:requestLegacyExternalStorage="true"
+        android:supportsRtl="true"
+        android:theme="@style/ComPDFKit.Theme.PDFViewer"
+        android:usesCleartextTraffic="true">
+
+        <activity
+            android:name="com.compdfkit.tools.common.pdf.CPDFDocumentActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
+            android:exported="true"
+            android:theme="@style/ComPDFKit.Theme.Light"
+            android:windowSoftInputMode="adjustPan">
+            <intent-filter tools:ignore="AppLinkUrlError"
+                android:scheme="http">
+                <action android:name="android.intent.action.VIEW" />
+                <action android:name="android.intent.action.SEND" />
+
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="application/pdf" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>

+ 4 - 0
PDFViewer/src/main/java/com/compdfkit/pdfviewer/home/SettingActivity.java

@@ -46,6 +46,7 @@ public class SettingActivity extends AppCompatActivity implements View.OnClickLi
 
         binding.swHighlightLink.setChecked(SettingDatas.isHighlightLink(this));
         binding.swHighlightForm.setChecked(SettingDatas.isHighlightForm(this));
+        binding.swFileSaveExtraSubset.setChecked(SettingDatas.isExtraFontSet(this));
 
         binding.swHighlightForm.setListener((buttonView, isChecked) -> {
             SettingDatas.setHighlightForm(this, isChecked);
@@ -53,6 +54,9 @@ public class SettingActivity extends AppCompatActivity implements View.OnClickLi
         binding.swHighlightLink.setListener((buttonView, isChecked) -> {
             SettingDatas.setHighlightLink(this, isChecked);
         });
+        binding.swFileSaveExtraSubset.setListener((buttonView, isChecked) -> {
+            SettingDatas.setFileSaveExtraFontSet(this, isChecked);
+        });
     }
 
     @Override

+ 1 - 0
PDFViewer/src/main/java/com/compdfkit/pdfviewer/home/datas/FunDatas.java

@@ -96,6 +96,7 @@ public class FunDatas {
         ReaderViewConfig readerViewConfig = configuration.readerViewConfig;
         readerViewConfig.linkHighlight = SettingDatas.isHighlightLink(context);
         readerViewConfig.formFieldHighlight = SettingDatas.isHighlightForm(context);
+        configuration.globalConfig.fileSaveExtraFontSubset = SettingDatas.isExtraFontSet(context);
         return configuration;
     }
 }

+ 10 - 0
PDFViewer/src/main/java/com/compdfkit/pdfviewer/home/datas/SettingDatas.java

@@ -29,4 +29,14 @@ public class SettingDatas {
     public static void setHighlightForm(Context context, boolean highLight){
         SpUtils.setBooleanValue(context, "highlight_form", highLight);
     }
+
+
+    public static boolean isExtraFontSet(Context context){
+        return SpUtils.getBooleanValue(context, "file_save_extra_font_set", true);
+    }
+
+    public static void setFileSaveExtraFontSet(Context context, boolean extra){
+        SpUtils.setBooleanValue(context, "file_save_extra_font_set", extra);
+    }
+
 }

+ 2 - 0
PDFViewer/src/main/java/com/compdfkit/pdfviewer/home/samples/DocumentEncryptionSamplesImpl.java

@@ -17,6 +17,7 @@ import androidx.fragment.app.Fragment;
 import com.compdfkit.core.document.CPDFDocument;
 import com.compdfkit.pdfviewer.R;
 import com.compdfkit.pdfviewer.home.HomeFunBean;
+import com.compdfkit.pdfviewer.home.datas.SettingDatas;
 import com.compdfkit.tools.common.utils.CToastUtil;
 import com.compdfkit.tools.common.utils.dialog.CAlertDialog;
 import com.compdfkit.tools.common.views.CVerifyPasswordDialogFragment;
@@ -59,6 +60,7 @@ public class DocumentEncryptionSamplesImpl extends OpenPDFSamplesImpl {
     private void showDocumentEncryptionDialog(CPDFDocument document){
         CDocumentEncryptionDialog encryptionDialog = CDocumentEncryptionDialog.newInstance();
         encryptionDialog.setDocument(document);
+        encryptionDialog.setSaveFileExtraFontSubset(SettingDatas.isExtraFontSet(fragment.getContext()));
         encryptionDialog.setEncryptionResultListener((isRemoveSecurity, result, file, password) -> {
             encryptionDialog.dismiss();
             int tipsResId;

+ 2 - 0
PDFViewer/src/main/java/com/compdfkit/pdfviewer/home/samples/WatermarkSamplesImpl.java

@@ -21,6 +21,7 @@ import com.compdfkit.core.watermark.CPDFWatermark;
 import com.compdfkit.pdfviewer.R;
 import com.compdfkit.pdfviewer.home.HomeFunBean;
 import com.compdfkit.pdfviewer.home.SelectWatermarkFunFragment;
+import com.compdfkit.pdfviewer.home.datas.SettingDatas;
 import com.compdfkit.tools.common.utils.CFileUtils;
 import com.compdfkit.tools.common.utils.CToastUtil;
 import com.compdfkit.tools.common.utils.dialog.CAlertDialog;
@@ -71,6 +72,7 @@ public class WatermarkSamplesImpl extends OpenPDFSamplesImpl {
             verifyDocument(filePath, uri, document -> {
                 CWatermarkEditDialog watermarkEditDialog = CWatermarkEditDialog.newInstance();
                 watermarkEditDialog.setDocument(document);
+                watermarkEditDialog.setSaveFileExtraFontSubset(SettingDatas.isExtraFontSet(fragment.getContext()));
                 watermarkEditDialog.setPageIndex(0);
                 watermarkEditDialog.setCompleteListener(pdfFile -> {
                     watermarkEditDialog.dismiss();

+ 15 - 0
PDFViewer/src/main/res/layout/activity_setting.xml

@@ -101,6 +101,21 @@
                         app:layout_constraintEnd_toEndOf="parent" />
                 </androidx.constraintlayout.widget.ConstraintLayout>
 
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="0.5dp"
+                    android:layout_marginHorizontal="8dp"
+                    android:background="?attr/dividerColor" />
+
+                <com.compdfkit.tools.common.views.pdfproperties.CPropertiesSwitchView
+                    android:id="@+id/sw_file_save_extra_subset"
+                    android:layout_width="match_parent"
+                    android:layout_height="48dp"
+                    android:checked="true"
+                    android:title="@string/the_fonts_data_is_saved_with_the_file"
+                    app:layout_constraintTop_toBottomOf="@id/tv_global_setting" />
+
+
                 <androidx.appcompat.widget.AppCompatTextView
                     android:id="@+id/tv_sdk_information"
                     android:layout_width="match_parent"

+ 3 - 0
PDFViewer/src/main/res/values-zh-rCN/strings.xml

@@ -62,4 +62,7 @@
     <string name="tools_compdfkit_sample_file_security">文档密码_compdfkit_ComPDFKit_PDF安全_示例文档.pdf</string>
     <string name="tools_compdfkit_sample_file_watermark">水印_ComPDFKit_示例文档.pdf</string>
 
+    <string name="the_fonts_data_is_saved_with_the_file">字体数据随文件一起保存</string>
+
+
 </resources>

+ 1 - 0
PDFViewer/src/main/res/values/strings.xml

@@ -66,4 +66,5 @@
     <string name="tools_compdfkit_sample_file_security">Password_compdfkit_ComPDFKit_Security_Sample_File.pdf</string>
     <string name="tools_compdfkit_sample_file_watermark">ComPDFKit_Watermark_Sample_File.pdf</string>
 
+    <string name="the_fonts_data_is_saved_with_the_file">The fonts data is saved with the file</string>
 </resources>

+ 2 - 0
Samples/src/main/java/com/compdfkit/samples/SampleApplication.java

@@ -13,6 +13,7 @@ package com.compdfkit.samples;
 import android.app.Application;
 
 import com.compdfkit.samples.samples.AnnotationImportExportTest;
+import com.compdfkit.samples.samples.AnnotationReplyTest;
 import com.compdfkit.samples.samples.AnnotationTest;
 import com.compdfkit.samples.samples.BackgroundTest;
 import com.compdfkit.samples.samples.BatesTest;
@@ -60,6 +61,7 @@ public class SampleApplication extends Application {
         samplesList.add(new TextSearchTest());
         samplesList.add(new AnnotationTest());
         samplesList.add(new AnnotationImportExportTest());
+        samplesList.add(new AnnotationReplyTest());
         samplesList.add(new InteractiveFormsTest());
         samplesList.add(new PDFPageTest());
         samplesList.add(new ImageExtractTest());

+ 81 - 0
Samples/src/main/java/com/compdfkit/samples/samples/AnnotationReplyTest.java

@@ -0,0 +1,81 @@
+package com.compdfkit.samples.samples;
+
+import com.compdfkit.core.annotation.CPDFAnnotation;
+import com.compdfkit.core.annotation.CPDFReplyAnnotation;
+import com.compdfkit.core.document.CPDFDocument;
+import com.compdfkit.samples.PDFSamples;
+import com.compdfkit.samples.R;
+import com.compdfkit.samples.util.FileUtils;
+import com.compdfkit.samples.util.OutputListener;
+
+import java.io.File;
+
+public class AnnotationReplyTest extends PDFSamples {
+
+    public AnnotationReplyTest(){
+        setTitle(R.string.annotation_reply_title);
+        setDescription(R.string.annotation_reply_desc);
+    }
+
+    @Override
+    protected void run(OutputListener outputListener) {
+        super.run(outputListener);
+        printHead();
+        printDividingLine();
+        CPDFDocument document = new CPDFDocument(context);
+        document.open(FileUtils.getAssetsTempFile(context, "Annotations.pdf"));
+
+
+        // ----------------------------------------
+        // Samples1 : create annotation reply info
+        // Get the first annotation on the first page
+        CPDFAnnotation annotation = document.pageAtIndex(0).getAnnotations().get(0);
+        annotation.setTitle("Guest");
+        if (annotation.getAllReplyAnnotations() == null || annotation.getAllReplyAnnotations().length == 0) {
+            outputListener.println("Annotation Type:" + annotation.getType().name());
+            CPDFReplyAnnotation replyAnnotation = annotation.createReplyAnnotation();
+            replyAnnotation.setMarkedAnnotState(CPDFAnnotation.MarkState.MARKED);
+            replyAnnotation.setReviewAnnotState(CPDFAnnotation.ReviewState.REVIEW_COMPLETED);
+            replyAnnotation.setTitle("Youna");
+            replyAnnotation.setContent("Hello ComPDFKit");
+            outputListener.println("Create Reply Annotation:");
+            outputListener.println("Title:" + replyAnnotation.getTitle());
+            outputListener.println("Content:" + replyAnnotation.getContent());
+            outputListener.println("ReviewState:" + replyAnnotation.getReviewAnnotState().name());
+            outputListener.println("MarkedState:" + replyAnnotation.getMarkedAnnotState().name());
+            outputListener.println("Create Reply Annotation End !!!");
+            printDividingLine();
+
+            CPDFReplyAnnotation replyAnnotation1 = annotation.createReplyAnnotation();
+            replyAnnotation1.setMarkedAnnotState(CPDFAnnotation.MarkState.UNMARKED);
+            replyAnnotation1.setReviewAnnotState(CPDFAnnotation.ReviewState.REVIEW_ACCEPTED);
+            replyAnnotation1.setTitle("C-Long");
+            replyAnnotation1.setContent("Hello World");
+            outputListener.println("Create Reply Annotation:");
+            outputListener.println("Title:" + replyAnnotation1.getTitle());
+            outputListener.println("Content:" + replyAnnotation1.getContent());
+            outputListener.println("ReviewState:" + replyAnnotation1.getReviewAnnotState().name());
+            outputListener.println("MarkedState:" + replyAnnotation1.getMarkedAnnotState().name());
+            outputListener.println("Create Reply Annotation End !!!");
+            printDividingLine();
+
+        }
+
+        // Samples 2: get all reply annotations
+        CPDFReplyAnnotation[] replyAnnotations = annotation.getAllReplyAnnotations();
+        outputListener.println("Get All Reply Annotations: ");
+        outputListener.println("Size: " + replyAnnotations.length);
+        outputListener.println("Annotation Type:" + annotation.getType().name());
+        if (replyAnnotations != null) {
+            for (CPDFReplyAnnotation replyAnnotation : replyAnnotations) {
+                printDividingLine();
+                outputListener.println("Title:" + replyAnnotation.getTitle());
+                outputListener.println("Content:" + replyAnnotation.getContent());
+                outputListener.println("ReviewState:" + replyAnnotation.getReviewAnnotState().name());
+                outputListener.println("MarkedState:" + replyAnnotation.getMarkedAnnotState().name());
+            }
+        }
+        saveSamplePDF(document, new File(outputDir(), "AnnotationTest/AnnotationReplyTest.pdf"), true);
+        printFooter();
+    }
+}

+ 3 - 0
Samples/src/main/res/values/strings.xml

@@ -68,6 +68,9 @@
     <string name="content_editor_title">ContentEditor</string>
     <string name="content_editor_desc">This example shows how to insert text and images through the content editing function.</string>
 
+    <string name="annotation_reply_title">AnnotationReply</string>
+    <string name="annotation_reply_desc">This example shows how to add comments, delete replies, etc.</string>
+
 
     <string name="tools_allowed">Allowed</string>
     <string name="tools_not_allowed">Not Allowed</string>