添加分享,打印,功能。

This commit is contained in:
ocean 2025-09-11 14:51:52 +08:00
parent 23e7e8f97b
commit 5323ad1324
8 changed files with 200 additions and 46 deletions

View File

@ -66,6 +66,16 @@
<data android:scheme="content" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>

View File

@ -0,0 +1,61 @@
package com.all.pdfreader.pro.app.ui.adapter
import android.content.Context
import android.net.Uri
import android.os.Bundle
import android.os.CancellationSignal
import android.os.ParcelFileDescriptor
import android.print.PageRange
import android.print.PrintAttributes
import android.print.PrintDocumentAdapter
import android.print.PrintDocumentInfo
import java.io.FileOutputStream
import java.io.InputStream
class PrintPdfAdapter(private val context: Context, private val uri: Uri) : PrintDocumentAdapter() {
override fun onLayout(
printAttributes: PrintAttributes?,
printAttributes2: PrintAttributes?,
cancellationSignal: CancellationSignal,
layoutResultCallback: LayoutResultCallback,
bundle: Bundle?
) {
if (cancellationSignal.isCanceled) {
layoutResultCallback.onLayoutCancelled()
} else {
layoutResultCallback.onLayoutFinished(
PrintDocumentInfo.Builder("AllPDF")
.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).build(), true
)
}
}
override fun onWrite(
pageRangeArr: Array<PageRange?>?,
parcelFileDescriptor: ParcelFileDescriptor,
cancellationSignal: CancellationSignal?,
writeResultCallback: WriteResultCallback
) {
try {
val openInputStream: InputStream? = context.contentResolver.openInputStream(uri)
val fileOutputStream = FileOutputStream(parcelFileDescriptor.fileDescriptor)
val bArr = ByteArray(1024)
while (true) {
val read = openInputStream?.read(bArr)
if (read != null) {
if (read > 0) {
fileOutputStream.write(bArr, 0, read)
} else {
writeResultCallback.onWriteFinished(arrayOf(PageRange.ALL_PAGES))
openInputStream.close()
fileOutputStream.close()
return
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}

View File

@ -1,20 +1,19 @@
package com.all.pdfreader.pro.app.ui.dialog
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.all.pdfreader.pro.app.R
import com.all.pdfreader.pro.app.databinding.DialogListMoreBinding
import com.all.pdfreader.pro.app.room.entity.PdfDocumentEntity
import com.all.pdfreader.pro.app.room.repository.PdfRepository
import com.all.pdfreader.pro.app.util.AppUtils.dpToPx
import com.all.pdfreader.pro.app.util.AppUtils.printPdfFile
import com.all.pdfreader.pro.app.util.AppUtils.setClickWithAnimation
import com.all.pdfreader.pro.app.util.FileUtils
import com.all.pdfreader.pro.app.util.AppUtils.shareFile
import com.all.pdfreader.pro.app.util.FileUtils.toFormatFileSize
import com.all.pdfreader.pro.app.util.FileUtils.toSlashDate
import com.all.pdfreader.pro.app.viewmodel.PdfViewModel
@ -22,7 +21,6 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kotlinx.coroutines.launch
import java.io.File
class ListMoreDialogFragment(val filePath: String) : BottomSheetDialogFragment() {
@ -97,6 +95,14 @@ class ListMoreDialogFragment(val filePath: String) : BottomSheetDialogFragment()
FileDetailsDialogFragment().show(parentFragmentManager, "FileDetailsDialogFragment")
dismiss()
}
binding.shareBtn.setOnClickListener {
shareFile(requireActivity(), File(pdfDocument.filePath))
dismiss()
}
binding.printBtn.setOnClickListener {
printPdfFile(requireActivity(), Uri.fromFile(File(pdfDocument.filePath)))
dismiss()
}
}
private fun updateCollectUi(b: Boolean) {

View File

@ -2,10 +2,38 @@ package com.all.pdfreader.pro.app.util
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.pdf.PdfRenderer
import android.net.Uri
import android.os.Bundle
import android.os.CancellationSignal
import android.os.ParcelFileDescriptor
import android.print.PageRange
import android.print.PrintAttributes
import android.print.PrintDocumentAdapter
import android.print.PrintDocumentInfo
import android.print.PrintManager
import android.print.pdf.PrintedPdfDocument
import android.view.View
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.webkit.MimeTypeMap
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.EditText
import android.widget.Toast
import androidx.core.content.FileProvider
import com.all.pdfreader.pro.app.R
import java.io.File
import java.io.FileOutputStream
import androidx.core.graphics.createBitmap
import androidx.print.PrintHelper
import com.all.pdfreader.pro.app.ui.adapter.PrintPdfAdapter
import com.shockwave.pdfium.PdfPasswordException
import com.shockwave.pdfium.PdfiumCore
import com.tom_roush.pdfbox.pdmodel.common.PDPageLabelRange
import java.io.IOException
object AppUtils {
@ -62,4 +90,81 @@ object AppUtils {
}, 200)
}
/**
* 分享文件自动识别 MIME 类型
* @param context 上下文
* @param file 要分享的文件
*/
fun shareFile(context: Context, file: File) {
try {
if (!file.exists()) {
Toast.makeText(context, context.getString(R.string.error_file_not_exist), Toast.LENGTH_SHORT).show()
return
}
val uri: Uri = FileProvider.getUriForFile(
context,
"${context.packageName}.fileprovider",
file
)
val mimeType = getMimeType(file) ?: "*/*"
val shareIntent = Intent(Intent.ACTION_SEND).apply {
type = mimeType
putExtra(Intent.EXTRA_STREAM, uri)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
context.startActivity(
Intent.createChooser(shareIntent, "share")
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
)
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 根据文件扩展名自动获取 MIME 类型
*/
private fun getMimeType(file: File): String? {
val extension = file.extension.lowercase()
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
}
/**
* 打印PDF传入uri
*/
fun printPdfFile(context: Context, uri: Uri?) {
try {
PdfiumCore(context).newDocument(
context.contentResolver.openFileDescriptor(
uri!!,
PDPageLabelRange.STYLE_ROMAN_LOWER
)
)
if (PrintHelper.systemSupportsPrint()) {
val printManager =
context.getSystemService(Context.PRINT_SERVICE) as PrintManager
val str = context.getString(R.string.app_name) + " Document"
printManager.print(
str,
PrintPdfAdapter(context, uri),
null as PrintAttributes?
)
return
}
Toast.makeText(context, R.string.device_does_not_support_printing, Toast.LENGTH_LONG).show()
} catch (e: PdfPasswordException) {
Toast.makeText(context, R.string.pdf_cant_print_password_protected, Toast.LENGTH_LONG).show()
e.printStackTrace()
} catch (e2: IOException) {
Toast.makeText(context, R.string.cannot_print_malformed_pdf, Toast.LENGTH_LONG).show()
e2.printStackTrace()
} catch (e3: java.lang.Exception) {
Toast.makeText(context, R.string.pdf_cannot_print_error, Toast.LENGTH_LONG).show()
e3.printStackTrace()
}
}
}

View File

@ -274,47 +274,6 @@ class PdfScanner(
return TimeUnit.MILLISECONDS.toHours(System.currentTimeMillis() - lastScan)
}
// private fun generateFastThumbnail(context: Context, pdfFile: File): String? {
// return try {
// val fileDescriptor =
// ParcelFileDescriptor.open(pdfFile, ParcelFileDescriptor.MODE_READ_ONLY)
// val pdfRenderer = PdfRenderer(fileDescriptor)
//
// if (pdfRenderer.pageCount > 0) {
// val page = pdfRenderer.openPage(0)
// // 创建 Bitmap
// val bitmap = createBitmap(page.width, page.height)
// val canvas = Canvas(bitmap)
// canvas.drawColor(Color.WHITE) // 填充白色背景
//
// page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
// page.close()
//
// // 保存到缓存目录
// val cacheDir = File(context.cacheDir, "thumbnails")
// if (!cacheDir.exists()) cacheDir.mkdirs()
// val thumbFile = File(cacheDir, pdfFile.nameWithoutExtension + ".jpg")
//
// FileOutputStream(thumbFile).use { out ->
// bitmap.compress(Bitmap.CompressFormat.JPEG, 80, out)
// }
//
// pdfRenderer.close()
// fileDescriptor.close()
//
// thumbFile.absolutePath
// } else {
// pdfRenderer.close()
// fileDescriptor.close()
// null
// }
// } catch (e: Exception) {
// e.printStackTrace()
// null
// }
// }
private fun generateFastThumbnail(
context: Context,
pdfFile: File,

View File

@ -169,6 +169,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/shareBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
@ -191,6 +192,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/printBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"

View File

@ -84,4 +84,8 @@
<string name="last_modified">Last Modified</string>
<string name="last_viewed">Last Viewed</string>
<string name="size">Size</string>
<string name="device_does_not_support_printing">Your device does not support printing</string>
<string name="pdf_cant_print_password_protected">Cannot print a password protected PDF file</string>
<string name="cannot_print_malformed_pdf">Cannot print a malformed PDF file</string>
<string name="pdf_cannot_print_error">Cannot print PDF file, Unknown error has occurred</string>
</resources>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 允许分享外部存储中的文件 -->
<external-path
name="external_files"
path="." />
</paths>