/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.documentsui.inspector; import static androidx.core.util.Preconditions.checkNotNull; import android.media.ExifInterface; import android.os.Bundle; import android.provider.DocumentsContract; import com.android.documentsui.base.Shared; import javax.annotation.Nullable; final class MetadataUtils { private MetadataUtils() {} static boolean hasGeoCoordinates(@Nullable Bundle metadata) { if (metadata == null) { return false; } return hasVideoCoordinates(metadata.getBundle(Shared.METADATA_KEY_VIDEO)) || hasExifGpsFields(metadata.getBundle(DocumentsContract.METADATA_EXIF)); } static boolean hasVideoCoordinates(@Nullable Bundle data) { return data != null && (data.containsKey(Shared.METADATA_VIDEO_LATITUDE) && data.containsKey(Shared.METADATA_VIDEO_LONGITUTE)); } static boolean hasExifGpsFields(@Nullable Bundle exif) { return exif != null && (exif.containsKey(ExifInterface.TAG_GPS_LATITUDE) && exif.containsKey(ExifInterface.TAG_GPS_LONGITUDE) && exif.containsKey(ExifInterface.TAG_GPS_LATITUDE_REF) && exif.containsKey(ExifInterface.TAG_GPS_LONGITUDE_REF)); } static float[] getGeoCoordinates(Bundle metadata) { assert hasGeoCoordinates(metadata); checkNotNull(metadata); Bundle bundle = metadata.getBundle(DocumentsContract.METADATA_EXIF); if (hasExifGpsFields(bundle)) { return getExifGpsCoords(bundle); } bundle = metadata.getBundle(Shared.METADATA_KEY_VIDEO); if (hasVideoCoordinates(bundle)) { return getVideoCoords(bundle); } // This should never happen, because callers should always check w/ hasGeoCoordinates first. throw new IllegalArgumentException("Invalid metadata bundle: " + metadata); } static float[] getExifGpsCoords(Bundle exif) { assert hasExifGpsFields(exif); String lat = exif.getString(ExifInterface.TAG_GPS_LATITUDE); String lon = exif.getString(ExifInterface.TAG_GPS_LONGITUDE); String latRef = exif.getString(ExifInterface.TAG_GPS_LATITUDE_REF); String lonRef = exif.getString(ExifInterface.TAG_GPS_LONGITUDE_REF); return new float[] { convertRationalLatLonToFloat(lat, latRef), convertRationalLatLonToFloat(lon, lonRef) }; } static float[] getVideoCoords(Bundle data) { assert hasVideoCoordinates(data); return new float[] { data.getFloat(Shared.METADATA_VIDEO_LATITUDE), data.getFloat(Shared.METADATA_VIDEO_LONGITUTE) }; } /** This founction is copied from {@link ExifInterface} */ private static float convertRationalLatLonToFloat(String rationalString, String ref) { try { String [] parts = rationalString.split(","); String [] pair; pair = parts[0].split("/"); double degrees = Double.parseDouble(pair[0].trim()) / Double.parseDouble(pair[1].trim()); pair = parts[1].split("/"); double minutes = Double.parseDouble(pair[0].trim()) / Double.parseDouble(pair[1].trim()); pair = parts[2].split("/"); double seconds = Double.parseDouble(pair[0].trim()) / Double.parseDouble(pair[1].trim()); double result = degrees + (minutes / 60.0) + (seconds / 3600.0); if ((ref.equals("S") || ref.equals("W"))) { return (float) -result; } return (float) result; } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) { // Not valid throw new IllegalArgumentException(); } } }