Я пытаюсь создать приложение, которое позволяет пользователю выбирать файл и отображать долготу/широту GPS, найденную в метаданных EXIF фотографии.
Я могу получить долготу/широту GPS, если пользователь выбирает изображение на вкладке «Последние» или на вкладке «Загрузки» (пример uri: content://com.android.providers.media.documents/document/image%3A1000000018).
Однако, когда пользователь выбирает изображение из хранилища (пример uri: content://com.android.externalstorage.documents/document/primary%3ADownload%2FPhilip%20Island.jpg), я получаю все данные EXIF, кроме GPS long/lat, которые приходит как нан или 0/1.
Я запросил READ_EXTERNAL_STORAGE и ACCESS_MEDIA_LOCATION как в манифесте, так и во время выполнения. Я также пробовал следующее:
Uri selecteduri = data.getData();
Cursor cursor = getContentResolver().query(selecteduri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
String[] parts = cursor.getString(0).split(":");
Uri photoUri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, parts[1]);
}
Единственный способ заставить его работать до сих пор — это построить путь к файлу с использованием URI (используя очень хакерский метод), чего мы не должны делать по очевидным причинам. Это мой код прямо сейчас:
ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@SuppressLint("Recycle")
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
// There are no request codes
Intent data = result.getData();
Uri selecteduri = data.getData();
InputStream stream = null;
try {
stream = getContentResolver().openInputStream(selecteduri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
ExifInterface exifInterface = null;
try {
exifInterface = new ExifInterface(stream);
} catch (IOException e) {
e.printStackTrace();
}
float[] output = new float[2];
exifInterface.getLatLong(output);
System.out.println("Uri: : " + selecteduri);
System.out.println("Lat: " + output[0]);
System.out.println("Long: " + output[1]);
System.out.println("Lat: " + exifInterface.getAttribute(ExifInterface.TAG_GPS_LATITUDE));
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
private ActivityResultLauncher<String> requestPermissionLauncher =
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
if (isGranted &&
checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(Manifest.permission.ACCESS_MEDIA_LOCATION) == PackageManager.PERMISSION_GRANTED) {
openImagePicker();
}
});
public void openImagePicker() {
Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
photoPickerIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION |
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
photoPickerIntent.setType("image/*");
photoPickerIntent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
someActivityResultLauncher.launch(createChooser(photoPickerIntent, "My Title"));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE);
}
if (checkSelfPermission(Manifest.permission.ACCESS_MEDIA_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissionLauncher.launch(Manifest.permission.ACCESS_MEDIA_LOCATION);
}
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(Manifest.permission.ACCESS_MEDIA_LOCATION) == PackageManager.PERMISSION_GRANTED) {
openImagePicker();
}
}
Что мне здесь не хватает? Спасибо!
Для первой схемы контента вы использовали ACTION_GET_CONTENT? Если да, предоставляет ли ACTION_OPEN_DOCUMENT ту же схему?
Я могу подтвердить то, что вы сказали. Интересный. Насколько мне известно, в документах этого нет. Так что выберите «Недавние» или «Изображения», и вы без проблем получите информацию о местоположении.
Интересный? Раздражающий! Требуется ACCESS_MEDIA_LOCATION для первой схемы контента, но я понятия не имею, какие разрешения необходимы для второй. MANAGE_EXTERNAL_STORAGE не помогает.
С помощью схемы file:// также можно прочитать lat,lon.
@blackapps, спасибо за предложения. Да, я использовал ACTION_GET_CONTENT. Пробовал MANAGE_EXTERNAL_STORAGE и ACTION_OPEN_DOCUMENT, все равно не работает. Спасибо за помощь!
Сначала вы должны преобразовать saf uri в uri mediastore.
Uri uri = MediaStore.getMediaUri(selectedUri);
будет делать свое дело.
Извините, я не знаю правильного имени, но Android Studio предложит правильное.
Да, об этом часто сообщалось здесь. Чтобы получить эту информацию о местоположении, вам также необходимо запросить разрешение на определение местоположения. И, возможно, MANAGE_EXTERNAL_STORAGE. Новым для меня является то, что не все провайдеры удаляют теги местоположения.