问题
Looking at the storage access changes introduced in Android 10 here, location informations are now redacted by default.
Google asks us to call setRequireOriginal()
on the "MediaStore" object with the media's uri as a parameter. This works when you fetch medias one by one, but what about when we query the ContentResolver for the whole gallery?
See this sample:
String[] projection = {
MediaStore.Files.FileColumns._ID,
MediaStore.Files.FileColumns.DATA,
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.Images.Media.DATE_TAKEN,
MediaStore.Images.Media.WIDTH,
MediaStore.Images.Media.HEIGHT,
MediaStore.Images.Media.LATITUDE, // <----- THIS
MediaStore.Images.Media.LONGITUDE, // <----- THIS
MediaStore.Images.Media.MIME_TYPE,
};
String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
+ MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE;
Uri queryUri = MediaStore.Files.getContentUri("external");
Cursor cursor = null;
MediaStore a ;
try {
cursor = context.getContentResolver().query(queryUri, projection, selection,
null, MediaStore.Images.Media.DATE_TAKEN + " DESC");
}
catch (NullPointerException ex){
}
Starting Q the latitude and longitude are always set to 0. Is there a way to get the location data for a batch of medias assuming the ACCESS_MEDIA_LOCATION
permission is added in the Manifest?
回答1:
Unfortunately, MediaStore.Images.Media.LATITUDE and MediaStore.Images.Media.LONGITUDE were deprecated in Android Q.
The work around for this is to use ExifInterface
like this:
Cursor cursor = null;
try {
String[] projection = {
MediaStore.Files.FileColumns._ID,
MediaStore.Images.Media.DATE_TAKEN,
MediaStore.Images.Media.WIDTH,
MediaStore.Images.Media.HEIGHT,
MediaStore.MediaColumns.TITLE,
MediaStore.Images.Media.MIME_TYPE,
MediaStore.Images.Media.LATITUDE,
MediaStore.Images.Media.LONGITUDE
};
cursor = getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
null,
null,
MediaStore.Images.Media.DATE_TAKEN + " DESC");
int idColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID);
int titleColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.TITLE);
int latColumn = BuildCompat.isAtLeastQ() ? -1
: cursor.getColumnIndexOrThrow(MediaStore.Images.Media.LATITUDE);
int longColumn = BuildCompat.isAtLeastQ() ? -1
: cursor.getColumnIndexOrThrow(MediaStore.Images.Media.LONGITUDE);
while (cursor.moveToNext()) {
Uri photoUri = Uri.withAppendedPath(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
cursor.getString(idColumn));
String title = cursor.getString(titleColumn);
final double[] latLong;
if (BuildCompat.isAtLeastQ()) {
photoUri = MediaStore.setRequireOriginal(photoUri);
InputStream stream = getContentResolver().openInputStream(photoUri);
if (stream == null) {
Log.w(TAG, "Got a null input stream for " + photoUri);
continue;
}
ExifInterface exifInterface = new ExifInterface(stream);
double[] returnedLatLong = exifInterface.getLatLong();
// If it returns null, fall back to {0.0, 0.0}.
latLong = returnedLatLong != null ? returnedLatLong : new double[2];
// After using ExifInterface, the stream should not be reused.
stream.close();
} else {
latLong = new double[]{
cursor.getFloat(latColumn),
cursor.getFloat(longColumn)
};
}
Log.i(TAG, title + " | lat: " + latLong[0] + " | lng: " + latLong[1]);
}
} catch (NullPointerException | IOException ex) {
Log.e(TAG, "Caught exception", ex);
} finally {
if (cursor != null) {
cursor.close();
}
}
This is the only way to get latitude & longitude of a photo on Android Q at the moment.
This requires holding the ACCESS_MEDIA_LOCATION permission.
来源:https://stackoverflow.com/questions/55186255/android-10-fetch-the-gallery-via-mediastore-with-location-information