1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.gallery3d.data;
18
19import android.media.ExifInterface;
20
21import com.android.gallery3d.R;
22import com.android.gallery3d.common.ExifTags;
23
24import java.io.IOException;
25import java.util.HashMap;
26import java.util.Iterator;
27import java.util.Map.Entry;
28import java.util.TreeMap;
29
30public class MediaDetails implements Iterable<Entry<Integer, Object>> {
31    @SuppressWarnings("unused")
32    private static final String TAG = "MediaDetails";
33
34    private TreeMap<Integer, Object> mDetails = new TreeMap<Integer, Object>();
35    private HashMap<Integer, Integer> mUnits = new HashMap<Integer, Integer>();
36
37    public static final int INDEX_TITLE = 1;
38    public static final int INDEX_DESCRIPTION = 2;
39    public static final int INDEX_DATETIME = 3;
40    public static final int INDEX_LOCATION = 4;
41    public static final int INDEX_WIDTH = 5;
42    public static final int INDEX_HEIGHT = 6;
43    public static final int INDEX_ORIENTATION = 7;
44    public static final int INDEX_DURATION = 8;
45    public static final int INDEX_MIMETYPE = 9;
46    public static final int INDEX_SIZE = 10;
47
48    // for EXIF
49    public static final int INDEX_MAKE = 100;
50    public static final int INDEX_MODEL = 101;
51    public static final int INDEX_FLASH = 102;
52    public static final int INDEX_FOCAL_LENGTH = 103;
53    public static final int INDEX_WHITE_BALANCE = 104;
54    public static final int INDEX_APERTURE = 105;
55    public static final int INDEX_SHUTTER_SPEED = 106;
56    public static final int INDEX_EXPOSURE_TIME = 107;
57    public static final int INDEX_ISO = 108;
58
59    // Put this last because it may be long.
60    public static final int INDEX_PATH = 200;
61
62    public static class FlashState {
63        private static int FLASH_FIRED_MASK = 1;
64        private static int FLASH_RETURN_MASK = 2 | 4;
65        private static int FLASH_MODE_MASK = 8 | 16;
66        private static int FLASH_FUNCTION_MASK = 32;
67        private static int FLASH_RED_EYE_MASK = 64;
68        private int mState;
69
70        public FlashState(int state) {
71            mState = state;
72        }
73
74        public boolean isFlashFired() {
75            return (mState & FLASH_FIRED_MASK) != 0;
76        }
77    }
78
79    public void addDetail(int index, Object value) {
80        mDetails.put(index, value);
81    }
82
83    public Object getDetail(int index) {
84        return mDetails.get(index);
85    }
86
87    public int size() {
88        return mDetails.size();
89    }
90
91    @Override
92    public Iterator<Entry<Integer, Object>> iterator() {
93        return mDetails.entrySet().iterator();
94    }
95
96    public void setUnit(int index, int unit) {
97        mUnits.put(index, unit);
98    }
99
100    public boolean hasUnit(int index) {
101        return mUnits.containsKey(index);
102    }
103
104    public int getUnit(int index) {
105        return mUnits.get(index);
106    }
107
108    private static void setExifData(MediaDetails details, ExifInterface exif, String tag,
109            int key) {
110        String value = exif.getAttribute(tag);
111        if (value != null) {
112            if (key == MediaDetails.INDEX_FLASH) {
113                MediaDetails.FlashState state = new MediaDetails.FlashState(
114                        Integer.valueOf(value.toString()));
115                details.addDetail(key, state);
116            } else {
117                details.addDetail(key, value);
118            }
119        }
120    }
121
122    public static void extractExifInfo(MediaDetails details, String filePath) {
123        try {
124            ExifInterface exif = new ExifInterface(filePath);
125            setExifData(details, exif, ExifInterface.TAG_FLASH, MediaDetails.INDEX_FLASH);
126            setExifData(details, exif, ExifInterface.TAG_IMAGE_WIDTH, MediaDetails.INDEX_WIDTH);
127            setExifData(details, exif, ExifInterface.TAG_IMAGE_LENGTH,
128                    MediaDetails.INDEX_HEIGHT);
129            setExifData(details, exif, ExifInterface.TAG_MAKE, MediaDetails.INDEX_MAKE);
130            setExifData(details, exif, ExifInterface.TAG_MODEL, MediaDetails.INDEX_MODEL);
131            setExifData(details, exif, ExifTags.TAG_APERTURE, MediaDetails.INDEX_APERTURE);
132            setExifData(details, exif, ExifTags.TAG_ISO, MediaDetails.INDEX_ISO);
133            setExifData(details, exif, ExifInterface.TAG_WHITE_BALANCE,
134                    MediaDetails.INDEX_WHITE_BALANCE);
135            setExifData(details, exif, ExifTags.TAG_EXPOSURE_TIME,
136                    MediaDetails.INDEX_EXPOSURE_TIME);
137
138            double data = exif.getAttributeDouble(ExifInterface.TAG_FOCAL_LENGTH, 0);
139            if (data != 0f) {
140                details.addDetail(MediaDetails.INDEX_FOCAL_LENGTH, data);
141                details.setUnit(MediaDetails.INDEX_FOCAL_LENGTH, R.string.unit_mm);
142            }
143        } catch (IOException ex) {
144            // ignore it.
145            Log.w(TAG, "", ex);
146        }
147    }
148}
149