Skip to content

Commit

Permalink
Potential fix for intermittent crash “kotlin.UninitializedPropertyAcc…
Browse files Browse the repository at this point in the history
…essException” that seems to happen when the app is in the background for a long time on Pdf Screen.

Upping versionCode to 51
  • Loading branch information
Dima-Android committed Mar 6, 2024
1 parent f763c5f commit 2f248a8
Show file tree
Hide file tree
Showing 18 changed files with 182 additions and 28 deletions.
17 changes: 17 additions & 0 deletions app/src/main/java/org/zotero/android/api/module/GeneralModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package org.zotero.android.api.module

import android.content.Context
import android.net.ConnectivityManager
import android.net.Uri
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.TypeAdapter
import com.google.gson.TypeAdapterFactory
import com.google.gson.reflect.TypeToken
import dagger.Module
import dagger.Provides
Expand All @@ -12,9 +15,12 @@ import kotlinx.serialization.json.Json
import org.zotero.android.api.ForGsonWithRoundedDecimals
import org.zotero.android.api.network.InternetConnectionStatusManager
import org.zotero.android.api.network.internetConnectionStatus
import org.zotero.android.architecture.serialization.SealedClassTypeAdapter
import org.zotero.android.architecture.serialization.UriTypeAdapter
import org.zotero.android.database.DbWrapper
import org.zotero.android.files.FormattedDoubleJsonSerializer
import javax.inject.Singleton
import kotlin.jvm.internal.Reflection

@Module
@DisableInstallInCheck
Expand Down Expand Up @@ -43,6 +49,17 @@ object GeneralModule {
val gsonBuilder = GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
.setLenient()
.registerTypeAdapterFactory(
object : TypeAdapterFactory {
override fun <T : Any> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T> {
val kclass = Reflection.getOrCreateKotlinClass(type.rawType)
return if (kclass.sealedSubclasses.any()) {
SealedClassTypeAdapter<T>(kclass, gson)
} else
gson.getDelegateAdapter(this, type)
}
})
.registerTypeAdapter(Uri::class.java, UriTypeAdapter)
return gsonBuilder
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import org.zotero.android.pdf.annotation.data.PdfAnnotationArgs
import org.zotero.android.pdf.annotationmore.data.PdfAnnotationMoreArgs
import org.zotero.android.pdf.annotationmore.editpage.data.PdfAnnotationEditPageArgs
import org.zotero.android.pdf.colorpicker.data.PdfReaderColorPickerArgs
import org.zotero.android.pdf.data.PdfReaderArgs
import org.zotero.android.pdf.settings.data.PdfSettingsArgs
import org.zotero.android.pdffilter.data.PdfFilterArgs
import org.zotero.android.screens.addnote.data.AddOrEditNoteArgs
Expand Down Expand Up @@ -35,7 +34,6 @@ object ScreenArguments {
lateinit var videoPlayerArgs: VideoPlayerArgs
lateinit var imageViewerArgs: ImageViewerArgs
lateinit var collectionPickerArgs: CollectionPickerArgs
lateinit var pdfReaderArgs: PdfReaderArgs
lateinit var pdfFilterArgs: PdfFilterArgs
lateinit var pdfSettingsArgs: PdfSettingsArgs
lateinit var pdfAnnotationArgs: PdfAnnotationArgs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fun NavGraphBuilder.allItemsScreen(
onOpenFile: (file: File, mimeType: String) -> Unit,
onOpenWebpage: (uri: Uri) -> Unit,
onPickFile: () -> Unit,
onShowPdf: () -> Unit,
onShowPdf: (String) -> Unit,
) {
composable(
route = CommonScreenDestinations.ALL_ITEMS,
Expand Down Expand Up @@ -69,7 +69,7 @@ fun NavGraphBuilder.itemDetailsScreen(
onOpenFile: (file: File, mimeType: String) -> Unit,
onOpenWebpage: (uri: Uri) -> Unit,
onPickFile: () -> Unit,
onShowPdf: () -> Unit,
onShowPdf: (String) -> Unit,
) {
composable(
route = CommonScreenDestinations.ITEM_DETAILS,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.zotero.android.architecture.navigation

import com.google.gson.Gson
import org.apache.commons.codec.binary.Base64
import org.apache.commons.io.IOUtils
import java.nio.charset.StandardCharsets
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class NavigationParamsMarshaller @Inject constructor(val gson: Gson) {

fun encodeObjectToBase64(data: Any): String {
val json = gson.toJson(data)
val encodedJson = encodeJsonToBase64(json)
return encodedJson
}

private fun encodeJsonToBase64(stringToEncode: String): String {
val bytes = IOUtils.toByteArray(stringToEncode);
val encoded: ByteArray = Base64.encodeBase64(bytes)
return String(encoded, StandardCharsets.US_ASCII)
}

inline fun <reified T> decodeObjectFromBase64(encodedJson: String): T {
val decodedJson = decodeJsonFromBase64Binary(encodedJson)
return unmarshal(decodedJson)
}

inline fun <reified T> unmarshal(data: String): T {
return gson.fromJson(data, T::class.java)
}

fun decodeJsonFromBase64Binary(encodedJson: String): String {
val bytes = IOUtils.toByteArray(encodedJson);
val decodedJson: ByteArray = Base64.decodeBase64(bytes)
return String(decodedJson, StandardCharsets.US_ASCII)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,10 @@ internal fun DashboardRootPhoneNavigation(
navigateToZoterWebViewScreen = navigation::toZoteroWebViewScreen,
navigateToTagFilter = navigation::toTagFilter,
navigateToCollectionPicker = navigation::toCollectionPicker,
onShowPdf = { navigation.toPdfScreen(
onShowPdf = { pdfScreenParams ->
navigation.toPdfScreen(
context = context,
pdfScreenParams = pdfScreenParams,
wasPspdfkitInitialized = wasPspdfkitInitialized
) },
)
Expand All @@ -135,7 +137,13 @@ internal fun DashboardRootPhoneNavigation(
onOpenFile = onOpenFile,
onOpenWebpage = onOpenWebpage,
onPickFile = { onPickFile(EventBusConstants.FileWasSelected.CallPoint.ItemDetails) },
onShowPdf = { navigation.toPdfScreen(context, wasPspdfkitInitialized) },
onShowPdf = { pdfScreenParams ->
navigation.toPdfScreen(
context = context,
wasPspdfkitInitialized = wasPspdfkitInitialized,
pdfScreenParams = pdfScreenParams
)
},
)

composable(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ internal fun DashboardRootTabletNavigationScreen(
onPickFile: (callPoint: EventBusConstants.FileWasSelected.CallPoint) -> Unit,
onOpenFile: (file: File, mimeType: String) -> Unit,
onOpenWebpage: (uri: Uri) -> Unit,
onShowPdf: () -> Unit,
onShowPdf: (String) -> Unit,
toAddOrEditNote: () -> Unit,
toZoteroWebViewScreen: (String) -> Unit,
viewModel: DashboardViewModel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ internal fun DashboardRootTopLevelTabletNavigation(
onOpenFile = onOpenFile,
onOpenWebpage = onOpenWebpage,
viewModel = viewModel,
onShowPdf = { navigation.toPdfScreen(context, wasPspdfkitInitialized) },
onShowPdf = { pdfScreenParams ->
navigation.toPdfScreen(
context = context,
wasPspdfkitInitialized = wasPspdfkitInitialized,
pdfScreenParams = pdfScreenParams
)
},
toAddOrEditNote = navigation::toAddOrEditNote,
toZoteroWebViewScreen = navigation::toZoteroWebViewScreen,
)
Expand All @@ -71,7 +77,7 @@ internal fun DashboardRootTopLevelTabletNavigation(
private fun NavGraphBuilder.dashboardScreen(
onPickFile: (callPoint: EventBusConstants.FileWasSelected.CallPoint) -> Unit,
onOpenFile: (file: File, mimeType: String) -> Unit,
onShowPdf: () -> Unit,
onShowPdf: (String) -> Unit,
toAddOrEditNote: () -> Unit,
toZoteroWebViewScreen: (String) -> Unit,
onOpenWebpage: (uri: Uri) -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import java.io.File
internal fun TabletRightPaneNavigation(
onPickFile: (callPoint: CallPoint) -> Unit,
onOpenFile: (file: File, mimeType: String) -> Unit,
onShowPdf: () -> Unit,
onShowPdf: (String) -> Unit,
toAddOrEditNote: () -> Unit,
toZoteroWebViewScreen: (String) -> Unit,
onOpenWebpage: (uri: Uri) -> Unit,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.zotero.android.architecture.serialization

import com.google.gson.Gson
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import kotlin.reflect.KClass

class SealedClassTypeAdapter<T : Any>(val kclass: KClass<Any>, val gson: Gson) : TypeAdapter<T>() {
override fun read(jsonReader: JsonReader): T? {
jsonReader.beginObject()
val nextName = jsonReader.nextName()
val innerClass = kclass.sealedSubclasses.firstOrNull {
it.simpleName!!.contains(nextName)
}
?: throw Exception("$nextName is not found to be a data class of the sealed class ${kclass.qualifiedName}")
val x = gson.fromJson<T>(jsonReader, innerClass.javaObjectType)
jsonReader.endObject()
return innerClass.objectInstance as T? ?: x
}

override fun write(out: JsonWriter, value: T) {
val jsonString = gson.toJson(value)
out.beginObject()
out.name(value.javaClass.canonicalName.splitToSequence(".").last()).jsonValue(jsonString)
out.endObject()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.zotero.android.architecture.serialization

import android.net.Uri
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonPrimitive
import com.google.gson.JsonSerializationContext
import com.google.gson.JsonSerializer
import java.lang.reflect.Type

object UriTypeAdapter : JsonDeserializer<Uri>, JsonSerializer<Uri> {

override fun deserialize(
json: JsonElement?,
typeOfT: Type?,
context: JsonDeserializationContext?
): Uri {
return Uri.parse(json?.asString.toString())
}

override fun serialize(
src: Uri?,
typeOfSrc: Type?,
context: JsonSerializationContext?
): JsonElement {
return JsonPrimitive(src.toString())
}
}
17 changes: 14 additions & 3 deletions app/src/main/java/org/zotero/android/pdf/PdfReaderNavigation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import androidx.compose.foundation.layout.width
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavType
import androidx.navigation.navArgument
import com.google.accompanist.navigation.animation.composable
import org.zotero.android.androidx.content.longToast
import org.zotero.android.architecture.navigation.ZoteroNavigation
Expand All @@ -24,6 +26,8 @@ import org.zotero.android.pdffilter.PdfFilterNavigation
import org.zotero.android.pdffilter.pdfFilterNavScreens
import org.zotero.android.pdffilter.toPdfFilterScreen

internal const val ARG_PDF_SCREEN = "pdfScreenArgs"

internal fun NavGraphBuilder.pdfReaderScreenAndNavigationForTablet(
navigation: ZoteroNavigation,
navigateToTagPickerDialog: () -> Unit,
Expand Down Expand Up @@ -129,7 +133,10 @@ private fun NavGraphBuilder.pdfScreen(
navigateToTagPicker: () -> Unit,
) {
composable(
route = PdfReaderDestinations.PDF_SCREEN,
route = "${PdfReaderDestinations.PDF_SCREEN}/{$ARG_PDF_SCREEN}",
arguments = listOf(
navArgument(ARG_PDF_SCREEN) { type = NavType.StringType },
),
) {
PdfReaderScreen(
onBack = onBack,
Expand All @@ -152,9 +159,13 @@ private object PdfReaderDestinations {
const val PDF_ANNOTATION_MORE_NAVIGATION = "pdfAnnotationMoreNavigation"
}

fun ZoteroNavigation.toPdfScreen(context: Context, wasPspdfkitInitialized: Boolean) {
fun ZoteroNavigation.toPdfScreen(
context: Context,
wasPspdfkitInitialized: Boolean,
pdfScreenParams: String,
) {
if (wasPspdfkitInitialized) {
navController.navigate(PdfReaderDestinations.PDF_SCREEN)
navController.navigate("${PdfReaderDestinations.PDF_SCREEN}/$pdfScreenParams")
} else {
context.longToast("Unable to open a PDF. PSPDFKIT was not initialized")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.Lifecycle
import org.zotero.android.architecture.ScreenArguments
import org.zotero.android.architecture.ui.CustomLayoutSize
import org.zotero.android.architecture.ui.ObserveLifecycleEvent
import org.zotero.android.pdf.reader.sidebar.PdfReaderSidebar
Expand Down Expand Up @@ -65,7 +64,7 @@ internal fun PdfReaderScreen(
}
}
CustomThemeWithStatusAndNavBars(isDarkTheme = viewState.isDark) {
val params = ScreenArguments.pdfReaderArgs
val params = viewModel.screenArgs
val uri = params.uri
val lazyListState = rememberLazyListState()
val layoutType = CustomLayoutSize.calculateLayoutType()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.commit
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import com.pspdfkit.annotations.Annotation
import com.pspdfkit.annotations.AnnotationFlags
Expand Down Expand Up @@ -67,6 +68,8 @@ import org.zotero.android.architecture.ScreenArguments
import org.zotero.android.architecture.ViewEffect
import org.zotero.android.architecture.ViewState
import org.zotero.android.architecture.ifFailure
import org.zotero.android.architecture.navigation.NavigationParamsMarshaller
import org.zotero.android.architecture.require
import org.zotero.android.database.DbRequest
import org.zotero.android.database.DbWrapper
import org.zotero.android.database.objects.AnnotationsConfig
Expand All @@ -88,6 +91,7 @@ import org.zotero.android.ktx.index
import org.zotero.android.ktx.isZoteroAnnotation
import org.zotero.android.ktx.key
import org.zotero.android.ktx.rounded
import org.zotero.android.pdf.ARG_PDF_SCREEN
import org.zotero.android.pdf.annotation.data.PdfAnnotationArgs
import org.zotero.android.pdf.annotation.data.PdfAnnotationColorResult
import org.zotero.android.pdf.annotation.data.PdfAnnotationCommentResult
Expand All @@ -112,6 +116,7 @@ import org.zotero.android.pdf.data.PageFitting
import org.zotero.android.pdf.data.PageLayoutMode
import org.zotero.android.pdf.data.PageScrollDirection
import org.zotero.android.pdf.data.PdfAnnotationChanges
import org.zotero.android.pdf.data.PdfReaderArgs
import org.zotero.android.pdf.data.PdfReaderCurrentThemeEventStream
import org.zotero.android.pdf.data.PdfReaderThemeDecider
import org.zotero.android.pdf.settings.data.PdfSettingsArgs
Expand Down Expand Up @@ -149,6 +154,8 @@ class PdfReaderViewModel @Inject constructor(
val annotationPreviewMemoryCache: AnnotationPreviewMemoryCache,
private val schemaController: SchemaController,
private val dateParser: DateParser,
private val navigationParamsMarshaller: NavigationParamsMarshaller,
stateHandle: SavedStateHandle,
) : BaseViewModel2<PdfReaderViewState, PdfReaderViewEffect>(PdfReaderViewState()) {

private var liveAnnotations: RealmResults<RItem>? = null
Expand Down Expand Up @@ -180,6 +187,11 @@ class PdfReaderViewModel @Inject constructor(

private var toolHistory = mutableListOf<AnnotationTool>()

val screenArgs: PdfReaderArgs by lazy {
val argsEncoded = stateHandle.get<String>(ARG_PDF_SCREEN).require()
navigationParamsMarshaller.decodeObjectFromBase64(argsEncoded)
}

@Subscribe(threadMode = ThreadMode.MAIN)
fun onEvent(result: PdfAnnotationMoreSaveResult) {
set(
Expand Down Expand Up @@ -450,7 +462,7 @@ class PdfReaderViewModel @Inject constructor(
}

private fun initState() {
val params = ScreenArguments.pdfReaderArgs
val params = this.screenArgs
val username = defaults.getUsername()
val userId = sessionDataEventStream.currentValue()!!.userId
val displayName = defaults.getDisplayName()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ internal fun AllItemsScreen(
navigateToImageViewerScreen: () -> Unit,
navigateToZoterWebViewScreen: (String) -> Unit,
navigateToTagFilter: () -> Unit,
onShowPdf: () -> Unit,
onShowPdf: (String) -> Unit,
) {
CustomThemeWithStatusAndNavBars(statusBarBackgroundColor = CustomTheme.colors.topBarBackgroundColor) {
val layoutType = CustomLayoutSize.calculateLayoutType()
Expand Down Expand Up @@ -89,7 +89,7 @@ internal fun AllItemsScreen(

is AllItemsViewEffect.OpenWebpage -> onOpenWebpage(consumedEffect.uri)
is AllItemsViewEffect.NavigateToPdfScreen -> {
onShowPdf()
onShowPdf(consumedEffect.params)
}

is AllItemsViewEffect.ShowVideoPlayer -> {
Expand Down
Loading

0 comments on commit 2f248a8

Please sign in to comment.