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