Skip to content

Commit

Permalink
[Fix] Use custom and stable parceling for persisted Uri.
Browse files Browse the repository at this point in the history
  • Loading branch information
zhanghai committed Oct 9, 2023
1 parent e834bbc commit 7091717
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ import kotlinx.parcelize.Parcelize
import kotlinx.parcelize.WriteWith
import me.zhanghai.android.files.app.contentResolver
import me.zhanghai.android.files.compat.DocumentsContractCompat
import me.zhanghai.android.files.compat.UriParcelerCompat
import me.zhanghai.android.files.compat.createOpenDocumentTreeIntentCompat
import me.zhanghai.android.files.storage.StorageVolumeListLiveData
import me.zhanghai.android.files.util.StableUriParceler
import me.zhanghai.android.files.util.getParcelableExtraSafe
import me.zhanghai.android.files.util.releasePersistablePermission
import me.zhanghai.android.files.util.takePersistablePermission
import me.zhanghai.android.files.util.valueCompat

@Parcelize
@JvmInline
value class DocumentTreeUri(val value: @WriteWith<UriParcelerCompat> Uri) : Parcelable {
value class DocumentTreeUri(val value: @WriteWith<StableUriParceler> Uri) : Parcelable {
val documentId: String
get() = DocumentsContract.getTreeDocumentId(value)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import kotlinx.parcelize.Parcelize
import kotlinx.parcelize.WriteWith
import me.zhanghai.android.files.app.contentResolver
import me.zhanghai.android.files.compat.DocumentsContractCompat
import me.zhanghai.android.files.compat.UriParcelerCompat
import me.zhanghai.android.files.util.StableUriParceler

@Parcelize
@JvmInline
value class DocumentUri(val value: @WriteWith<UriParcelerCompat> Uri) : Parcelable {
value class DocumentUri(val value: @WriteWith<StableUriParceler> Uri) : Parcelable {
val documentId: String
get() = DocumentsContract.getDocumentId(value)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@ import java8.nio.file.Path
import java8.nio.file.WatchEvent
import java8.nio.file.WatchKey
import java8.nio.file.WatchService
import me.zhanghai.android.files.compat.UriParcelerCompat
import me.zhanghai.android.files.provider.common.ByteString
import me.zhanghai.android.files.provider.common.ByteStringListPath
import me.zhanghai.android.files.provider.common.UriAuthority
import me.zhanghai.android.files.provider.common.toByteString
import me.zhanghai.android.files.provider.content.resolver.Resolver
import me.zhanghai.android.files.provider.content.resolver.ResolverException
import me.zhanghai.android.files.util.ValueParceler.write
import me.zhanghai.android.files.util.StableUriParceler
import me.zhanghai.android.files.util.readParcelable
import java.io.File
import java.net.URI
Expand Down Expand Up @@ -138,15 +137,15 @@ internal class ContentPath : ByteStringListPath<ContentPath> {
private constructor(source: Parcel) : super(source) {
fileSystem = source.readParcelable()!!
//uri = source.readParcelable()
uri = UriParcelerCompat.create(source)
uri = StableUriParceler.create(source)
}

override fun writeToParcel(dest: Parcel, flags: Int) {
super.writeToParcel(dest, flags)

dest.writeParcelable(fileSystem, flags)
//dest.writeParcelable(uri, flags)
with(UriParcelerCompat) { uri.write(dest, flags) }
with(StableUriParceler) { uri.write(dest, flags) }
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import java8.nio.file.PathMatcher
import java8.nio.file.WatchService
import java8.nio.file.attribute.UserPrincipalLookupService
import java8.nio.file.spi.FileSystemProvider
import me.zhanghai.android.files.compat.UriParcelerCompat
import me.zhanghai.android.files.provider.common.ByteString
import me.zhanghai.android.files.provider.common.ByteStringBuilder
import me.zhanghai.android.files.provider.common.ByteStringListPathCreator
import me.zhanghai.android.files.provider.common.toByteString
import me.zhanghai.android.files.util.StableUriParceler
import java.io.IOException

internal class DocumentFileSystem(
Expand Down Expand Up @@ -117,7 +117,7 @@ internal class DocumentFileSystem(

override fun writeToParcel(dest: Parcel, flags: Int) {
//dest.writeParcelable(treeUri, flags)
with(UriParcelerCompat) { treeUri.write(dest, flags) }
with(StableUriParceler) { treeUri.write(dest, flags) }
}

companion object {
Expand All @@ -129,7 +129,7 @@ internal class DocumentFileSystem(
val CREATOR = object : Parcelable.Creator<DocumentFileSystem> {
override fun createFromParcel(source: Parcel): DocumentFileSystem {
//val treeUri = source.readParcelable<Uri>()!!
val treeUri = UriParcelerCompat.create(source)!!
val treeUri = StableUriParceler.create(source)!!
return DocumentFileSystemProvider.getOrNewFileSystem(treeUri)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@
* All Rights Reserved.
*/

package me.zhanghai.android.files.compat
package me.zhanghai.android.files.util

import android.net.Uri
import android.os.Build
import android.os.Parcel
import androidx.annotation.RequiresApi
import kotlinx.parcelize.Parceler
import me.zhanghai.android.files.hiddenapi.RestrictedHiddenApi
import me.zhanghai.android.files.util.lazyReflectedMethod

// Work around Uri parceling changes in
// https://android.googlesource.com/platform/frameworks/base/+/97f621d81fc51de240ba73bc008d997e0eea7939
// (and the String8 change in API 30).
object UriParcelerCompat : Parceler<Uri?> {
// The built-in parceling of Uri isn't guaranteed to be stable and has changed 2 times, so we should
// always use our own parceling for persistence.
// The reading code here is backwards compatible in that it also handles built-in parceling of Uri,
// including the changes in
// https://android.googlesource.com/platform/frameworks/base/+/97f621d81fc51de240ba73bc008d997e0eea7939 ,
// and the String8 change in API 30.
object StableUriParceler : Parceler<Uri?> {
private const val NULL_TYPE_ID = 0
private const val STRING_URI_TYPE_ID = 1
private const val OPAQUE_URI_TYPE_ID = 2
Expand All @@ -31,9 +33,17 @@ object UriParcelerCompat : Parceler<Uri?> {
private val parcelReadString8Method by lazyReflectedMethod(Parcel::class.java, "readString8")

override fun create(parcel: Parcel): Uri? {
val uriString = parcel.readString() ?: return null
// Parcel.readParcelableCreator()
parcel.readString() ?: return null
// Uri.CREATOR.createFromParcel()
return if (uriString.startsWith(Uri::class.java.name)) {
readUri(parcel)
} else {
Uri.parse(uriString)
}
}

// Uri.CREATOR.createFromParcel()
private fun readUri(parcel: Parcel): Uri? {
val uriString = when (val typeId = parcel.readInt()) {
NULL_TYPE_ID -> return null
// Uri.StringUri.readFrom()
Expand Down Expand Up @@ -62,7 +72,7 @@ object UriParcelerCompat : Parceler<Uri?> {
HIERARCHICAL_URI_TYPE_ID -> {
// Uri.HierarchicalUri.readFrom()
// Scheme can be null for HierarchicalUri.
val scheme = parcel.readUriString() as String?
val scheme = parcel.readUriString()
// Assume that we never persist a Uri with only a scheme.
if (scheme != null && scheme.contains(':')) {
scheme
Expand Down Expand Up @@ -102,13 +112,6 @@ object UriParcelerCompat : Parceler<Uri?> {
return Uri.parse(uriString)
}

private fun Parcel.readUriString(): String? =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
parcelReadString8Method.invoke(this) as String?
} else {
readString()
}

// Uri.Part.readFrom()
private fun readEncodedPart(parcel: Parcel): String? =
when (val representation = parcel.readInt()) {
Expand Down Expand Up @@ -141,7 +144,14 @@ object UriParcelerCompat : Parceler<Uri?> {
"/${encodedPathPart}"
}

private fun Parcel.readUriString(): String? =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
parcelReadString8Method.invoke(this) as String?
} else {
readString()
}

override fun Uri?.write(parcel: Parcel, flags: Int) {
parcel.writeParcelable(this, flags)
parcel.writeString(this?.toString())
}
}

0 comments on commit 7091717

Please sign in to comment.