16f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling/* 26f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * Copyright (C) 2013 The Android Open Source Project 36f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * 46f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * Licensed under the Apache License, Version 2.0 (the "License"); 56f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * you may not use this file except in compliance with the License. 66f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * You may obtain a copy of the License at 76f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * 86f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * http://www.apache.org/licenses/LICENSE-2.0 96f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * 106f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * Unless required by applicable law or agreed to in writing, software 116f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * distributed under the License is distributed on an "AS IS" BASIS, 126f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * See the License for the specific language governing permissions and 146f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * limitations under the License. 156f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling */ 166f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 176f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberlingpackage com.android.camera.data; 186f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 19b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberlingimport android.content.Context; 20e2fb9943fb2d5a51a651f138d88473bf7f62e0b9Sascha Haeberlingimport android.util.SparseIntArray; 216f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 222bca210e5fc8a77685775ffb403096167b017dceAngus Kongimport com.android.camera.debug.Log; 23a16e7b50f3148f581439509279f242092e254309ztenghuiimport com.android.camera.exif.ExifInterface; 24a16e7b50f3148f581439509279f242092e254309ztenghuiimport com.android.camera.exif.ExifTag; 256f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberlingimport com.android.camera2.R; 266f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 276f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberlingimport java.io.FileNotFoundException; 286f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberlingimport java.io.IOException; 296f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberlingimport java.util.Iterator; 306f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberlingimport java.util.Map.Entry; 316f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberlingimport java.util.TreeMap; 326f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 336f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberlingpublic class MediaDetails implements Iterable<Entry<Integer, Object>> { 346f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling @SuppressWarnings("unused") 352bca210e5fc8a77685775ffb403096167b017dceAngus Kong private static final Log.Tag TAG = new Log.Tag("MediaDetails"); 366f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 376f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling private TreeMap<Integer, Object> mDetails = new TreeMap<Integer, Object>(); 38e2fb9943fb2d5a51a651f138d88473bf7f62e0b9Sascha Haeberling private SparseIntArray mUnits = new SparseIntArray(); 396f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 406f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_TITLE = 1; 416f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_DESCRIPTION = 2; 426f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_DATETIME = 3; 436f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_LOCATION = 4; 446f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_WIDTH = 5; 456f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_HEIGHT = 6; 466f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_ORIENTATION = 7; 476f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_DURATION = 8; 486f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_MIMETYPE = 9; 496f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_SIZE = 10; 506f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 516f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling // for EXIF 526f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_MAKE = 100; 536f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_MODEL = 101; 546f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_FLASH = 102; 556f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_FOCAL_LENGTH = 103; 566f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_WHITE_BALANCE = 104; 576f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_APERTURE = 105; 586f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_SHUTTER_SPEED = 106; 596f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_EXPOSURE_TIME = 107; 606f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_ISO = 108; 616f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 626f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling // Put this last because it may be long. 636f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static final int INDEX_PATH = 200; 646f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 656f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static class FlashState { 666f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling private static int FLASH_FIRED_MASK = 1; 676f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling private static int FLASH_RETURN_MASK = 2 | 4; 686f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling private static int FLASH_MODE_MASK = 8 | 16; 696f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling private static int FLASH_FUNCTION_MASK = 32; 706f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling private static int FLASH_RED_EYE_MASK = 64; 716f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling private int mState; 726f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 736f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public FlashState(int state) { 746f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling mState = state; 756f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 766f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 776f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public boolean isFlashFired() { 786f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling return (mState & FLASH_FIRED_MASK) != 0; 796f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 806f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 816f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 826f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public void addDetail(int index, Object value) { 836f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling mDetails.put(index, value); 846f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 856f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 866f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public Object getDetail(int index) { 876f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling return mDetails.get(index); 886f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 896f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 906f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public int size() { 916f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling return mDetails.size(); 926f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 936f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 946f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling @Override 956f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public Iterator<Entry<Integer, Object>> iterator() { 966f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling return mDetails.entrySet().iterator(); 976f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 986f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 996f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public void setUnit(int index, int unit) { 1006f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling mUnits.put(index, unit); 1016f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 1026f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 1036f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public boolean hasUnit(int index) { 104e2fb9943fb2d5a51a651f138d88473bf7f62e0b9Sascha Haeberling return mUnits.indexOfKey(index) >= 0; 1056f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 1066f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 1076f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public int getUnit(int index) { 1086f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling return mUnits.get(index); 1096f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 1106f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 1116f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling private static void setExifData(MediaDetails details, ExifTag tag, 1126f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling int key) { 1136f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling if (tag != null) { 1146f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling String value = null; 1156f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling int type = tag.getDataType(); 1166f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling if (type == ExifTag.TYPE_UNSIGNED_RATIONAL || type == ExifTag.TYPE_RATIONAL) { 1176f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling value = String.valueOf(tag.getValueAsRational(0).toDouble()); 1186f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } else if (type == ExifTag.TYPE_ASCII) { 1196f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling value = tag.getValueAsString(); 1206f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } else { 1216f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling value = String.valueOf(tag.forceGetValueAsLong(0)); 1226f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 1236f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling if (key == MediaDetails.INDEX_FLASH) { 1246f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling MediaDetails.FlashState state = new MediaDetails.FlashState( 1258ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde Integer.valueOf(value)); 1266f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling details.addDetail(key, state); 1276f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } else { 1286f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling details.addDetail(key, value); 1296f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 1306f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 1316f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 1326f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 1336f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling /** 1346f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * Extracts data from the EXIF of the given file and stores it in the 1356f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling * MediaDetails instance. 1366f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling */ 1376f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling public static void extractExifInfo(MediaDetails details, String filePath) { 1386f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling ExifInterface exif = new ExifInterface(); 1396f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling try { 1406f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling exif.readExif(filePath); 1416f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } catch (FileNotFoundException e) { 1426f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling Log.w(TAG, "Could not find file to read exif: " + filePath, e); 1436f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } catch (IOException e) { 1446f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling Log.w(TAG, "Could not read exif from file: " + filePath, e); 1456f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 1466f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling 1476f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling setExifData(details, exif.getTag(ExifInterface.TAG_FLASH), 1486f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling MediaDetails.INDEX_FLASH); 1496f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling setExifData(details, exif.getTag(ExifInterface.TAG_IMAGE_WIDTH), 1506f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling MediaDetails.INDEX_WIDTH); 1516f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling setExifData(details, exif.getTag(ExifInterface.TAG_IMAGE_LENGTH), 1526f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling MediaDetails.INDEX_HEIGHT); 1536f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling setExifData(details, exif.getTag(ExifInterface.TAG_MAKE), 1546f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling MediaDetails.INDEX_MAKE); 1556f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling setExifData(details, exif.getTag(ExifInterface.TAG_MODEL), 1566f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling MediaDetails.INDEX_MODEL); 1576f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling setExifData(details, exif.getTag(ExifInterface.TAG_APERTURE_VALUE), 1586f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling MediaDetails.INDEX_APERTURE); 1596f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling setExifData(details, exif.getTag(ExifInterface.TAG_ISO_SPEED_RATINGS), 1606f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling MediaDetails.INDEX_ISO); 1616f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling setExifData(details, exif.getTag(ExifInterface.TAG_WHITE_BALANCE), 1626f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling MediaDetails.INDEX_WHITE_BALANCE); 1636f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling setExifData(details, exif.getTag(ExifInterface.TAG_EXPOSURE_TIME), 1646f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling MediaDetails.INDEX_EXPOSURE_TIME); 1656f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling ExifTag focalTag = exif.getTag(ExifInterface.TAG_FOCAL_LENGTH); 1666f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling if (focalTag != null) { 1676f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling details.addDetail(MediaDetails.INDEX_FOCAL_LENGTH, 1686f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling focalTag.getValueAsRational(0).toDouble()); 1696f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling details.setUnit(MediaDetails.INDEX_FOCAL_LENGTH, R.string.unit_mm); 1706f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 1716f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling } 172b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling 173b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling /** 174b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling * Returns a (localized) string for the given duration (in seconds). 175b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling */ 176b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling public static String formatDuration(final Context context, long seconds) { 177b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling long h = seconds / 3600; 178b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling long m = (seconds - h * 3600) / 60; 179b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling long s = seconds - (h * 3600 + m * 60); 180b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling String durationValue; 181b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling if (h == 0) { 182b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling durationValue = String.format(context.getString(R.string.details_ms), m, s); 183b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling } else { 184b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling durationValue = String.format(context.getString(R.string.details_hms), h, m, s); 185b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling } 186b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling return durationValue; 187b0a5929b1dd0ddc2729e23ba95afdb43a1aecfd5Sascha Haeberling } 1886f64b50db6565bc6454304fd20c0c4020b297bb7Sascha Haeberling} 189