From 17c7c84296a29febe9704626af1e557353313086 Mon Sep 17 00:00:00 2001 From: Pratyush Date: Fri, 7 Apr 2023 17:37:50 +0530 Subject: [PATCH] rewrite DocumentPropertiesLoader in kotlin --- .../app/grapheneos/pdfviewer/PdfViewer.java | 8 +- .../DocumentPropertiesAsyncTaskLoader.java | 48 ++++++ .../loader/DocumentPropertiesLoader.java | 149 ------------------ .../loader/DocumentPropertiesLoader.kt | 113 +++++++++++++ .../pdfviewer/loader/DocumentProperty.kt | 36 +++++ ...JsPropertiesToDocumentPropertyConverter.kt | 49 ++++++ app/src/main/res/values/arrays.xml | 17 -- app/src/main/res/values/strings.xml | 13 ++ 8 files changed, 263 insertions(+), 170 deletions(-) create mode 100644 app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentPropertiesAsyncTaskLoader.java delete mode 100644 app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentPropertiesLoader.java create mode 100644 app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentPropertiesLoader.kt create mode 100644 app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentProperty.kt create mode 100644 app/src/main/java/app/grapheneos/pdfviewer/loader/PDFJsPropertiesToDocumentPropertyConverter.kt delete mode 100644 app/src/main/res/values/arrays.xml diff --git a/app/src/main/java/app/grapheneos/pdfviewer/PdfViewer.java b/app/src/main/java/app/grapheneos/pdfviewer/PdfViewer.java index 474efcc..a9ea7bd 100644 --- a/app/src/main/java/app/grapheneos/pdfviewer/PdfViewer.java +++ b/app/src/main/java/app/grapheneos/pdfviewer/PdfViewer.java @@ -45,7 +45,7 @@ import app.grapheneos.pdfviewer.fragment.DocumentPropertiesFragment; import app.grapheneos.pdfviewer.fragment.PasswordPromptFragment; import app.grapheneos.pdfviewer.fragment.JumpToPageFragment; import app.grapheneos.pdfviewer.ktx.ViewKt; -import app.grapheneos.pdfviewer.loader.DocumentPropertiesLoader; +import app.grapheneos.pdfviewer.loader.DocumentPropertiesAsyncTaskLoader; import app.grapheneos.pdfviewer.viewModel.PasswordStatus; import java.io.IOException; @@ -191,7 +191,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader final Bundle args = new Bundle(); args.putString(KEY_PROPERTIES, properties); - runOnUiThread(() -> LoaderManager.getInstance(PdfViewer.this).restartLoader(DocumentPropertiesLoader.ID, args, PdfViewer.this)); + runOnUiThread(() -> LoaderManager.getInstance(PdfViewer.this).restartLoader(DocumentPropertiesAsyncTaskLoader.ID, args, PdfViewer.this)); } @JavascriptInterface @@ -476,14 +476,14 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader @NonNull @Override public Loader> onCreateLoader(int id, Bundle args) { - return new DocumentPropertiesLoader(this, args.getString(KEY_PROPERTIES), mNumPages, mUri); + return new DocumentPropertiesAsyncTaskLoader(this, args.getString(KEY_PROPERTIES), mNumPages, mUri); } @Override public void onLoadFinished(@NonNull Loader> loader, List data) { mDocumentProperties = data; setToolbarTitleWithDocumentName(); - LoaderManager.getInstance(this).destroyLoader(DocumentPropertiesLoader.ID); + LoaderManager.getInstance(this).destroyLoader(DocumentPropertiesAsyncTaskLoader.ID); } @Override diff --git a/app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentPropertiesAsyncTaskLoader.java b/app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentPropertiesAsyncTaskLoader.java new file mode 100644 index 0000000..62d9745 --- /dev/null +++ b/app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentPropertiesAsyncTaskLoader.java @@ -0,0 +1,48 @@ +package app.grapheneos.pdfviewer.loader; + +import android.content.Context; +import android.net.Uri; + +import androidx.annotation.Nullable; +import androidx.loader.content.AsyncTaskLoader; + +import java.util.List; + +public class DocumentPropertiesAsyncTaskLoader extends AsyncTaskLoader> { + + public static final String TAG = "DocumentPropertiesLoader"; + + public static final int ID = 1; + + private final String mProperties; + private final int mNumPages; + private final Uri mUri; + + public DocumentPropertiesAsyncTaskLoader(Context context, String properties, int numPages, Uri uri) { + super(context); + + mProperties = properties; + mNumPages = numPages; + mUri = uri; + } + + + @Override + protected void onStartLoading() { + forceLoad(); + } + + @Nullable + @Override + public List loadInBackground() { + + DocumentPropertiesLoader loader = new DocumentPropertiesLoader( + getContext(), + mProperties, + mNumPages, + mUri + ); + + return loader.loadAsList(); + } +} diff --git a/app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentPropertiesLoader.java b/app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentPropertiesLoader.java deleted file mode 100644 index a45070a..0000000 --- a/app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentPropertiesLoader.java +++ /dev/null @@ -1,149 +0,0 @@ -package app.grapheneos.pdfviewer.loader; - -import android.content.Context; -import android.database.Cursor; -import android.graphics.Typeface; -import android.net.Uri; -import android.provider.OpenableColumns; -import android.text.SpannableStringBuilder; -import android.text.Spanned; -import android.text.style.StyleSpan; -import android.util.Log; - -import androidx.loader.content.AsyncTaskLoader; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.text.ParseException; -import java.util.ArrayList; -import java.util.List; - -import app.grapheneos.pdfviewer.R; -import app.grapheneos.pdfviewer.Utils; - -public class DocumentPropertiesLoader extends AsyncTaskLoader> { - public static final String TAG = "DocumentPropertiesLoader"; - - public static final int ID = 1; - - private final String mProperties; - private final int mNumPages; - private final Uri mUri; - - private Cursor mCursor; - - public DocumentPropertiesLoader(Context context, String properties, int numPages, Uri uri) { - super(context); - - mProperties = properties; - mNumPages = numPages; - mUri = uri; - } - - @Override - public List loadInBackground() { - final Context context = getContext(); - - final String[] names = context.getResources().getStringArray(R.array.property_names); - final List properties = new ArrayList<>(names.length); - - mCursor = context.getContentResolver().query(mUri, null, null, null, null); - if (mCursor != null) { - mCursor.moveToFirst(); - - final int indexName = mCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); - if (indexName >= 0) { - properties.add(getProperty(null, names[0], mCursor.getString(indexName))); - } - - final int indexSize = mCursor.getColumnIndex(OpenableColumns.SIZE); - if (indexSize >= 0) { - final long fileSize = Long.parseLong(mCursor.getString(indexSize)); - properties.add(getProperty(null, names[1], Utils.parseFileSize(fileSize))); - } - - mCursor.close(); - } - - try { - final JSONObject json = new JSONObject(mProperties); - - properties.add(getProperty(json, names[2], "Title")); - properties.add(getProperty(json, names[3], "Author")); - properties.add(getProperty(json, names[4], "Subject")); - properties.add(getProperty(json, names[5], "Keywords")); - properties.add(getProperty(json, names[6], "CreationDate")); - properties.add(getProperty(json, names[7], "ModDate")); - properties.add(getProperty(json, names[8], "Producer")); - properties.add(getProperty(json, names[9], "Creator")); - properties.add(getProperty(json, names[10], "PDFFormatVersion")); - properties.add(getProperty(null, names[11], String.valueOf(mNumPages))); - - return properties; - } catch (JSONException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public void deliverResult(List properties) { - if (isReset()) { - onReleaseResources(); - } else if (isStarted()) { - super.deliverResult(properties); - } - } - - @Override - protected void onStartLoading() { - forceLoad(); - } - - @Override - protected void onStopLoading() { - cancelLoad(); - } - - @Override - public void onCanceled(List properties) { - super.onCanceled(properties); - - onReleaseResources(); - } - - @Override - protected void onReset() { - super.onReset(); - - onStopLoading(); - onReleaseResources(); - } - - private void onReleaseResources() { - if (mCursor != null) { - mCursor.close(); - mCursor = null; - } - } - - private CharSequence getProperty(final JSONObject json, String name, String specName) { - final SpannableStringBuilder property = new SpannableStringBuilder(name).append(":\n"); - final String value = json != null ? json.optString(specName, "-") : specName; - - if (specName != null && specName.endsWith("Date")) { - final Context context = getContext(); - try { - property.append(value.equals("-") ? value : Utils.parseDate(value)); - } catch (ParseException e) { - Log.w(TAG, e.getMessage() + " for " + value + " at offset: " + e.getErrorOffset()); - property.append(context.getString(R.string.document_properties_invalid_date)); - } - } else { - property.append(value); - } - property.setSpan(new StyleSpan(Typeface.BOLD), 0, name.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - return property; - } -} diff --git a/app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentPropertiesLoader.kt b/app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentPropertiesLoader.kt new file mode 100644 index 0000000..9b70643 --- /dev/null +++ b/app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentPropertiesLoader.kt @@ -0,0 +1,113 @@ +package app.grapheneos.pdfviewer.loader + +import android.content.Context +import android.graphics.Typeface +import android.net.Uri +import android.provider.OpenableColumns +import android.text.SpannableStringBuilder +import android.text.Spanned +import android.text.style.StyleSpan +import android.util.Log +import app.grapheneos.pdfviewer.R +import app.grapheneos.pdfviewer.Utils +import org.json.JSONException + +class DocumentPropertiesLoader( + private val context: Context, + private val properties: String, + private val numPages: Int, + private val mUri: Uri +) { + + fun loadAsList(): List { + return load().map { item -> + val name = context.getString(item.key.nameResource) + val value = item.value + + SpannableStringBuilder() + .append(name) + .append(":\n") + .append(value) + .apply { + setSpan( + StyleSpan(Typeface.BOLD), + 0, + name.length, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ) + } + } + } + + fun load(): Map { + val result = mutableMapOf() + result.addFileProperties() + result.addPageSizeProperty() + result.addPDFJsProperties() + return result + } + + private fun MutableMap.addPageSizeProperty() { + this[DocumentProperty.Pages] = java.lang.String.valueOf(numPages) + } + + private fun MutableMap.addFileProperties() { + putAll(getFileProperties()) + } + + private fun MutableMap.addPDFJsProperties() { + putAll(getPDFJsProperties()) + } + + private fun getPDFJsProperties(): Map { + return try { + PDFJsPropertiesToDocumentPropertyConverter( + properties, + context.getString(R.string.document_properties_invalid_date), + parseExceptionListener = { parseException, value -> + Log.w( + DocumentPropertiesAsyncTaskLoader.TAG, + "${parseException.message} for $value at offset: ${parseException.errorOffset}" + ) + } + ).convert() + } catch (e: JSONException) { + Log.w( + DocumentPropertiesAsyncTaskLoader.TAG, + "invalid properties" + ) + emptyMap() + } + } + + private fun getFileProperties(): Map { + val collections = mutableMapOf() + val proj = arrayOf( + OpenableColumns.DISPLAY_NAME, + OpenableColumns.SIZE + ) + + context.contentResolver.query( + mUri, + proj, + null, + null + )?.use { cursor -> + cursor.moveToFirst() + val indexName: Int = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME) + + if (indexName >= 0) { + collections[DocumentProperty.FileName] = cursor.getString(indexName) + } + + val indexSize: Int = cursor.getColumnIndex(OpenableColumns.SIZE) + if (indexSize >= 0) { + val fileSize: Long = cursor.getString(indexSize).toLong() + collections[DocumentProperty.FileSize] = Utils.parseFileSize(fileSize) + } + } + return collections + } + + +} \ No newline at end of file diff --git a/app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentProperty.kt b/app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentProperty.kt new file mode 100644 index 0000000..8be68e3 --- /dev/null +++ b/app/src/main/java/app/grapheneos/pdfviewer/loader/DocumentProperty.kt @@ -0,0 +1,36 @@ +package app.grapheneos.pdfviewer.loader + +import androidx.annotation.StringRes +import app.grapheneos.pdfviewer.R + +private const val TITLE_KEY = "Title" +private const val AUTHOR_KEY = "Author" +private const val SUBJECT_KEY = "Subject" +private const val KEYWORDS_KEY = "Keywords" +private const val CREATION_DATE_KEY = "CreationDate" +private const val MODIFY_DATE_KEY = "ModDate" +private const val PRODUCER_KEY = "Producer" +private const val CREATOR_KEY = "Creator" +private const val PDF_VERSION_KEY = "PDFFormatVersion" + +const val DEFAULT_VALUE = "-" + +enum class DocumentProperty( + val key: String = "", + @StringRes val nameResource: Int, + val isDate: Boolean = false +) { + FileName(key = "", nameResource = R.string.file_name), + FileSize(key = "", nameResource = R.string.file_size), + Pages(key = "", nameResource = R.string.pages), + Title(key = TITLE_KEY, nameResource = R.string.title), + Author(key = AUTHOR_KEY, nameResource = R.string.author), + Subject(key = SUBJECT_KEY, nameResource = R.string.subject), + Keywords(key = KEYWORDS_KEY, nameResource = R.string.keywords), + CreationDate(key = CREATION_DATE_KEY, nameResource = R.string.creation_date, isDate = true), + ModifyDate(key = MODIFY_DATE_KEY, nameResource = R.string.modify_date, isDate = true), + Producer(key = PRODUCER_KEY, nameResource = R.string.producer), + Creator(key = CREATOR_KEY, nameResource = R.string.creator), + PDFVersion(key = PDF_VERSION_KEY, nameResource = R.string.pdf_version); + +} \ No newline at end of file diff --git a/app/src/main/java/app/grapheneos/pdfviewer/loader/PDFJsPropertiesToDocumentPropertyConverter.kt b/app/src/main/java/app/grapheneos/pdfviewer/loader/PDFJsPropertiesToDocumentPropertyConverter.kt new file mode 100644 index 0000000..95e5ddd --- /dev/null +++ b/app/src/main/java/app/grapheneos/pdfviewer/loader/PDFJsPropertiesToDocumentPropertyConverter.kt @@ -0,0 +1,49 @@ +package app.grapheneos.pdfviewer.loader + +import app.grapheneos.pdfviewer.Utils +import org.json.JSONException +import org.json.JSONObject +import java.text.ParseException +import kotlin.jvm.Throws + +class PDFJsPropertiesToDocumentPropertyConverter( + private val properties: String, + private val propertyInvalidDate: String, + private val parseExceptionListener: (e: ParseException, value: String) -> Unit +) { + + @Throws(JSONException::class) + fun convert(): Map { + val result = mutableMapOf() + + val json = JSONObject(properties) + addJsonProperties(json, result) + return result + } + + private fun addJsonProperties( + json: JSONObject, + collections: MutableMap + ) { + for (documentProperty in DocumentProperty.values()) { + val key = documentProperty.key + if (key.isEmpty()) continue + val value = json.optString(key, DEFAULT_VALUE) + collections[documentProperty] = prettify(documentProperty, value) + } + } + + private fun prettify(property: DocumentProperty, value: String): String { + if (value != DEFAULT_VALUE && property.isDate) { + return try { + Utils.parseDate(value) + } catch (parseException: ParseException) { + parseExceptionListener.invoke(parseException, value) + propertyInvalidDate + } + } + return value + } + + +} \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml deleted file mode 100644 index d9d1b85..0000000 --- a/app/src/main/res/values/arrays.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - File name - File size - Title - Author - Subject - Keywords - Creation date - Modify date - Producer - Creator - PDF version - Pages - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 79cb1e5..a129a93 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -31,4 +31,17 @@ Enter the password to decrypt this PDF file Open Cancel + + File name + File size + Title + Author + Subject + Keywords + Creation date + Modify date + Producer + Creator + PDF version + Pages