0

I'm trying to create an app that allows the user to select a file and display the GPS long/lat found in the photo EXIF metadata.

I can get the GPS long/lat if the user selects an image from the recent tab or Downloads tab(example uri: content://com.android.providers.media.documents/document/image%3A1000000018).

However, when the user selects an image from storage(example uri: content://com.android.externalstorage.documents/document/primary%3ADownload%2FPhilip%20Island.jpg), I get all EXIF data except GPS long/lat which comes as nan or 0/1.

I have requested READ_EXTERNAL_STORAGE and ACCESS_MEDIA_LOCATION both in the manifest and during runtime. I've also tried the following:

  • ACTION_GET_CONTENT intent's Intent.FLAG_GRANT_READ_URI_PERMISSION flag
  • uri = MediaStore.setRequireOriginal(uri);
  • Using the contentResolver to create a URI as below:
 ​ 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]);  
}

The only way I've gotten it to work so far is by constructing the file path using the URI(using a very hacky method), which we shouldn't do for obvious reasons. This is my code right now:​​

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();
    }
}

What am I missing here? Thanks!

  • Yes this has been reported often here. To get this location information you also need to request location permission. And maybe MANAGE_EXTERNAL_STORAGE. New for me is that not all providers strip location tags. – blackapps Oct 19 '22 at 04:48
  • For the first content scheme, did you use ACTION_GET_CONTENT? If so, does ACTION_OPEN_DOCUMENT deliver the same scheme? – blackapps Oct 19 '22 at 06:03
  • I can confirm what you said. Interesting. This is not in the documents as far as i know. So pick from Recent or Images and you get location info without hassle. – blackapps Oct 19 '22 at 07:20
  • Interesting? Annoying! Need ACCESS_MEDIA_LOCATION for the first content scheme but i have no idea which permission(s) further needed for the second. MANAGE_EXTERNAL_STORAGE does not help. – blackapps Oct 19 '22 at 11:10
  • Using a file:// scheme lat,lon can be read too. – blackapps Oct 19 '22 at 11:43
  • @blackapps , thanks for the suggestions. Yes I used ACTION_GET_CONTENT. Tried MANAGE_EXTERNAL_STORAGE and ACTION_OPEN_DOCUMENT, still doesn't work. Thanks for the help! – Uvin Abeysinghe Nov 03 '22 at 22:57

1 Answers1

0

You should convert the saf uri to a mediastore uri first.

Uri uri = MediaStore.getMediaUri(selectedUri); 

will do the trick.

Sorry, out of mind i do not know the right name, but Android Studio will suggest the right one.

blackapps
  • 8,011
  • 2
  • 11
  • 25