-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expand file tree
/
Copy pathUploadableFile.kt
More file actions
170 lines (146 loc) · 5.29 KB
/
UploadableFile.kt
File metadata and controls
170 lines (146 loc) · 5.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package fr.free.nrw.commons.filepicker
import android.annotation.SuppressLint
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Parcel
import android.os.Parcelable
import androidx.exifinterface.media.ExifInterface
import fr.free.nrw.commons.upload.FileUtils
import fr.free.nrw.commons.upload.ImageCoordinates
import java.io.File
import java.io.IOException
import java.util.Date
import timber.log.Timber
class UploadableFile : Parcelable {
val contentUri: Uri
val file: File
var hasUnsupportedFormat: Boolean = false
constructor(contentUri: Uri, file: File) {
this.contentUri = contentUri
this.file = file
}
constructor(file: File) {
this.file = file
this.contentUri = Uri.fromFile(File(file.path))
}
private constructor(parcel: Parcel) {
contentUri = parcel.readParcelable(Uri::class.java.classLoader)!!
file = parcel.readSerializable() as File
hasUnsupportedFormat = parcel.readInt() == 1
}
fun getFilePath(): String {
return file.path
}
fun getMediaUri(): Uri {
return Uri.parse(getFilePath())
}
fun getMimeType(context: Context): String? {
return FileUtils.getMimeType(context, getMediaUri())
}
override fun describeContents(): Int = 0
/**
* First try to get the file creation date from EXIF, else fall back to Content Provider (CP)
*/
fun getFileCreatedDate(context: Context): DateTimeWithSource? {
return getDateTimeFromExif() ?: getFileCreatedDateFromCP(context)
}
/**
* Get filePath creation date from URI using all possible content providers
*/
private fun getFileCreatedDateFromCP(context: Context): DateTimeWithSource? {
return try {
val cursor: Cursor? = context.contentResolver.query(contentUri, null, null, null, null)
cursor?.use {
val lastModifiedColumnIndex = cursor
.getColumnIndex(
"last_modified"
).takeIf { it != -1 }
?: cursor.getColumnIndex("datetaken")
if (lastModifiedColumnIndex == -1) return null // No valid column found
cursor.moveToFirst()
DateTimeWithSource(
cursor.getLong(
lastModifiedColumnIndex
), DateTimeWithSource.CP_SOURCE)
}
} catch (e: Exception) {
Timber.tag("UploadableFile").d(e)
null
}
}
/**
* Indicates whether the EXIF contains the location (both latitude and longitude).
*/
fun hasLocation(): Boolean {
return try {
val exif = ExifInterface(file.absolutePath)
ImageCoordinates(exif, null).imageCoordsExists
} catch (e: IOException) {
Timber.tag("UploadableFile").d(e)
false
}
}
/**
* Get filePath creation date from URI using EXIF data
*/
private fun getDateTimeFromExif(): DateTimeWithSource? {
return try {
val exif = ExifInterface(file.absolutePath)
val dateTimeSubString = exif.getAttribute(ExifInterface.TAG_DATETIME_ORIGINAL)
if (dateTimeSubString != null) {
val year = dateTimeSubString.substring(0, 4).toInt()
val month = dateTimeSubString.substring(5, 7).toInt()
val day = dateTimeSubString.substring(8, 10).toInt()
val dateCreatedString = "%04d-%02d-%02d".format(year, month, day)
if (dateCreatedString.length == 10) {
@SuppressLint("RestrictedApi")
val dateTime = exif.dateTimeOriginal
if (dateTime != null) {
val date = Date(dateTime)
return DateTimeWithSource(date, dateCreatedString, DateTimeWithSource.EXIF_SOURCE)
}
}
}
null
} catch (e: Exception) {
Timber.tag("UploadableFile").d(e)
null
}
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeParcelable(contentUri, flags)
parcel.writeSerializable(file)
parcel.writeInt(if (hasUnsupportedFormat) 1 else 0)
}
class DateTimeWithSource {
companion object {
const val CP_SOURCE = "contentProvider"
const val EXIF_SOURCE = "exif"
}
val epochDate: Long
var dateString: String? = null
val source: String
constructor(epochDate: Long, source: String) {
this.epochDate = epochDate
this.source = source
}
constructor(date: Date, source: String) {
epochDate = date.time
this.source = source
}
constructor(date: Date, dateString: String, source: String) {
epochDate = date.time
this.dateString = dateString
this.source = source
}
}
companion object CREATOR : Parcelable.Creator<UploadableFile> {
override fun createFromParcel(parcel: Parcel): UploadableFile {
return UploadableFile(parcel)
}
override fun newArray(size: Int): Array<UploadableFile?> {
return arrayOfNulls(size)
}
}
}