You can list albums on your Android phone, and you should access image files via scoped storage.
To find photos on Android device, refer to Android Find/Search Photos/Images in Album.
Code to find photos
fun findImagesInAlbum(albumId: String) { val contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI val projections = arrayOf( MediaStore.Images.ImageColumns._ID, MediaStore.Images.ImageColumns.DATE_TAKEN, MediaStore.Images.ImageColumns.DISPLAY_NAME, ) val selection = "${MediaStore.Images.ImageColumns.BUCKET_ID} == ?" val selectionArgs = arrayOf( albumId ) contentResolver.query(contentUri, projections, selection, selectionArgs, "${MediaStore.Images.ImageColumns.DATE_TAKEN} ASC")?.use { cursor -> if (cursor.moveToFirst()) { val idIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns._ID) val dateTakenIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATE_TAKEN) val displayNameIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DISPLAY_NAME) do { val mediaId = cursor.getLong(idIndex) val filename = cursor.getString(displayNameIndex) val millis = cursor.getLong(dateTakenIndex) // scoped storage - access file via uri instead of filepath + filename var uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mediaId) // read file contentResolver.openInputStream(uri).use { stream -> val exif = ExifInterface(stream) }) } } }}
Option 1: MediaStore.MediaColumns.DATE_TAKEN
You can get DATE_TAKEN which is in epoch milli seconds.
Indexed value of MediaMetadataRetriever#METADATA_KEY_DATE or ExifInterface#TAG_DATETIME_ORIGINAL extracted from this media item.
Note that images must define both ExifInterface#TAG_DATETIME_ORIGINAL and ExifInterface#TAG_OFFSET_TIME_ORIGINAL to reliably determine this value in relation to the epoch. Value is a non-negative timestamp measured as the number of milliseconds since 1970-01-01T00:00:00Z.
NOTE: DATE_TAKEN
might be miscalculated if some photos have ExifInterface#TAG_OFFSET_TIME_ORIGINAL
or GPS info, while others photos doesn't have such info.
val millis = cursor.getLong(dateTakenIndex)// convert epoch millis to device timezone dateval date = LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.systemDefault())// convert epoch millis to UTC dateval dateUtc = LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneOffset.UTC)
NOTE: If you need to convert millis to DateTime, you need to specify a timezone. Using UTC would gain the most persistence result, or you can guess the timezone of the photo.
Option 2: ExifInterface.TAG_DATETIME_ORIGINAL
The date and time when the original image data was generated. For a DSC the date and time the picture was taken are recorded. The format is "YYYY:MM:DD HH:MM:SS" with time shown in 24-hour format
// scoped storage - access file via uri instead of filepath + filenamevar uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mediaId)// read filevar exifDate: LocalDateTime? = nullcontentResolver.openInputStream(uri)?.use { stream -> val exif = ExifInterface(stream) val exifDateFormatter = DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss") var exifDateString = exif.getAttribute(ExifInterface.TAG_DATETIME_ORIGINAL) if (exifDateString == null) { exifDateString = exif.getAttribute(ExifInterface.TAG_DATETIME) } if (exifDateString != null) { exifDate = LocalDateTime.parse(exifDateString, exifDateFormatter) }}
NOTE: if MediaStore.MediaColumns.DATE_TAKEN
gives you epoch millis seconds, ExifInterface.TAG_DATETIME_ORIGINAL
gives you the date and time of the device when it was taken.
Option 3: Extra Date from Filename
Filename usually comes in the format of IMG_20190907_143933.jpg
, which gives you a clue of the date. There is no guarantee though.
val filenameRegex = """(\w|-|_|\s)(?<year>\d{4})(?<month>\d{2})(?<day>\d{2})(-|_|\s)(?<hour>\d{2})(?<minute>\d{2})(?<second>\d{2})""".toRegex() // (-|_|\s|\.|$)fun filenameToDate(filename: String): LocalDateTime? { // IMG_20190907_143933.jpg val m = filenameRegex.find(filename) if (m != null) { val (_, year, month, day, _, hour, minute, second) = m.destructured return LocalDateTime.of(year.toInt(), month.toInt(), day.toInt(), hour.toInt(), minute.toInt(), second.toInt()) } return null}
Usage
val filename = cursor.getString(displayNameIndex)val filenameDate = filenameToDate(filename)
NOTE: The filename date usually is the same as the exif date.
Timezone?
Refer Android Get Photo Timezone.