From 6f64b50db6565bc6454304fd20c0c4020b297bb7 Mon Sep 17 00:00:00 2001 From: Sascha Haeberling Date: Wed, 14 Aug 2013 16:23:18 -0700 Subject: Brings back the details menu with most EXIF data in it. Some are still missing and will come back later. Bug: 10330505 Change-Id: I7bc44b19fac5b47557d5feae3ed969040ac3ae9b --- src/com/android/camera/CameraActivity.java | 23 +- src/com/android/camera/data/DataUtils.java | 49 ++++ src/com/android/camera/data/LocalData.java | 6 +- src/com/android/camera/data/LocalMediaData.java | 58 +++-- src/com/android/camera/data/MediaDetails.java | 171 ++++++++++++++ src/com/android/camera/data/SimpleViewData.java | 5 + src/com/android/camera/ui/DetailsDialog.java | 297 ++++++++++++++++++++++++ 7 files changed, 591 insertions(+), 18 deletions(-) create mode 100644 src/com/android/camera/data/DataUtils.java create mode 100644 src/com/android/camera/data/MediaDetails.java create mode 100644 src/com/android/camera/ui/DetailsDialog.java (limited to 'src/com') diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java index 099b5035f..98ea363eb 100644 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -29,6 +29,7 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.drawable.ColorDrawable; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -54,10 +55,12 @@ import com.android.camera.data.FixedFirstDataAdapter; import com.android.camera.data.FixedLastDataAdapter; import com.android.camera.data.LocalData; import com.android.camera.data.LocalDataAdapter; +import com.android.camera.data.MediaDetails; import com.android.camera.data.SimpleViewData; import com.android.camera.util.ApiHelper; import com.android.camera.ui.CameraSwitcher; import com.android.camera.ui.CameraSwitcher.CameraSwitchListener; +import com.android.camera.ui.DetailsDialog; import com.android.camera.ui.FilmStripView; import com.android.camera.util.CameraUtil; import com.android.camera.util.PhotoSphereHelper.PanoramaViewHelper; @@ -93,7 +96,7 @@ public class CameraActivity extends Activity private static final int SUPPORT_SHOW_ON_MAP = 1 << 8; private static final int SUPPORT_ALL = 0xffffffff; - /** This data adapter is used by FilmStirpView. */ + /** This data adapter is used by FilmStripView. */ private LocalDataAdapter mDataAdapter; /** This data adapter represents the real local camera data. */ private LocalDataAdapter mWrappedDataAdapter; @@ -412,6 +415,12 @@ public class CameraActivity extends Activity @Override public boolean onOptionsItemSelected(MenuItem item) { + int currentDataId = mFilmStripView.getCurrentId(); + if (currentDataId < 0) { + return false; + } + final LocalData localData = mDataAdapter.getLocalData(currentDataId); + // Handle presses on the action bar items switch (item.getItemId()) { case R.id.action_delete: @@ -439,7 +448,17 @@ public class CameraActivity extends Activity // TODO: add the functionality. return true; case R.id.action_details: - // TODO: add the functionality. + (new AsyncTask() { + @Override + protected MediaDetails doInBackground(Void... params) { + return localData.getMediaDetails(CameraActivity.this); + } + + @Override + protected void onPostExecute(MediaDetails mediaDetails) { + DetailsDialog.create(CameraActivity.this, mediaDetails).show(); + } + }).execute(); return true; case R.id.action_show_on_map: // TODO: add the functionality. diff --git a/src/com/android/camera/data/DataUtils.java b/src/com/android/camera/data/DataUtils.java new file mode 100644 index 000000000..0b074d824 --- /dev/null +++ b/src/com/android/camera/data/DataUtils.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2013 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.camera.data; + +import android.content.ContentResolver; +import android.database.Cursor; +import android.net.Uri; +import android.provider.MediaStore; + +public class DataUtils { + + /** + * Get the file path from a Media storage URI. + */ + public static String getPathFromURI(ContentResolver contentResolver, Uri contentUri) { + String[] proj = { + MediaStore.Images.Media.DATA + }; + Cursor cursor = contentResolver.query(contentUri, proj, null, null, null); + if (cursor == null) { + return null; + } + try { + int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + if (!cursor.moveToFirst()) { + return null; + } else { + return cursor.getString(columnIndex); + } + } finally { + cursor.close(); + } + } + +} diff --git a/src/com/android/camera/data/LocalData.java b/src/com/android/camera/data/LocalData.java index 7d6dfefc6..61714e243 100644 --- a/src/com/android/camera/data/LocalData.java +++ b/src/com/android/camera/data/LocalData.java @@ -23,7 +23,6 @@ import android.net.Uri; import android.view.View; import com.android.camera.ui.FilmStripView; -import com.android.camera.util.PhotoSphereHelper.PanoramaViewHelper; import java.util.Comparator; @@ -102,6 +101,11 @@ public interface LocalData extends FilmStripView.ImageData { */ Uri getContentUri(); + /** + * Return media data (such as EXIF) for the item. + */ + MediaDetails getMediaDetails(Context context); + /** * Returns the type of the local data defined by {@link LocalData}. * diff --git a/src/com/android/camera/data/LocalMediaData.java b/src/com/android/camera/data/LocalMediaData.java index d5a929d36..e55274f06 100644 --- a/src/com/android/camera/data/LocalMediaData.java +++ b/src/com/android/camera/data/LocalMediaData.java @@ -35,12 +35,13 @@ import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; -import com.android.camera.util.CameraUtil; import com.android.camera.ui.FilmStripView; +import com.android.camera.util.CameraUtil; import com.android.camera.util.PhotoSphereHelper; import com.android.camera2.R; import java.io.File; +import java.text.DateFormat; import java.util.Date; /** @@ -53,12 +54,13 @@ public abstract class LocalMediaData implements LocalData { protected long id; protected String title; protected String mimeType; - protected long dateTaken; - protected long dateModified; + protected long dateTakenInSeconds; + protected long dateModifiedInSeconds; protected String path; // width and height should be adjusted according to orientation. protected int width; protected int height; + protected long sizeInBytes; /** The panorama metadata information of this media data. */ protected PhotoSphereHelper.PanoramaMetadata mPanoramaMetadata; @@ -74,12 +76,12 @@ public abstract class LocalMediaData implements LocalData { @Override public long getDateTaken() { - return dateTaken; + return dateTakenInSeconds; } @Override public long getDateModified() { - return dateModified; + return dateModifiedInSeconds; } @Override @@ -214,6 +216,7 @@ public abstract class LocalMediaData implements LocalData { public static final int COL_ORIENTATION = 6; public static final int COL_WIDTH = 7; public static final int COL_HEIGHT = 8; + public static final int COL_SIZE = 9; static final Uri CONTENT_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; @@ -232,6 +235,7 @@ public abstract class LocalMediaData implements LocalData { MediaStore.Images.ImageColumns.ORIENTATION, // 6, int, 0, 90, 180, 270 MediaStore.Images.ImageColumns.WIDTH, // 7, int MediaStore.Images.ImageColumns.HEIGHT, // 8, int + MediaStore.Images.ImageColumns.SIZE, // 9, long }; private static final int mSupportedUIActions = @@ -251,8 +255,8 @@ public abstract class LocalMediaData implements LocalData { d.id = c.getLong(COL_ID); d.title = c.getString(COL_TITLE); d.mimeType = c.getString(COL_MIME_TYPE); - d.dateTaken = c.getLong(COL_DATE_TAKEN); - d.dateModified = c.getLong(COL_DATE_MODIFIED); + d.dateTakenInSeconds = c.getLong(COL_DATE_TAKEN); + d.dateModifiedInSeconds = c.getLong(COL_DATE_MODIFIED); d.path = c.getString(COL_DATA); d.orientation = c.getInt(COL_ORIENTATION); d.width = c.getInt(COL_WIDTH); @@ -281,6 +285,7 @@ public abstract class LocalMediaData implements LocalData { d.width = d.height; d.height = b; } + d.sizeInBytes = c.getLong(COL_SIZE); return d; } @@ -288,7 +293,7 @@ public abstract class LocalMediaData implements LocalData { public String toString() { return "Photo:" + ",data=" + path + ",mimeType=" + mimeType + "," + width + "x" + height + ",orientation=" + orientation - + ",date=" + new Date(dateTaken); + + ",date=" + new Date(dateTakenInSeconds); } @Override @@ -319,6 +324,23 @@ public abstract class LocalMediaData implements LocalData { return baseUri.buildUpon().appendPath(String.valueOf(id)).build(); } + @Override + public MediaDetails getMediaDetails(Context context) { + DateFormat formater = DateFormat.getDateTimeInstance(); + MediaDetails mediaDetails = new MediaDetails(); + mediaDetails.addDetail(MediaDetails.INDEX_TITLE, title); + mediaDetails.addDetail(MediaDetails.INDEX_WIDTH, width); + mediaDetails.addDetail(MediaDetails.INDEX_HEIGHT, height); + mediaDetails.addDetail(MediaDetails.INDEX_PATH, path); + mediaDetails.addDetail(MediaDetails.INDEX_DATETIME, + formater.format(new Date(dateModifiedInSeconds * 1000))); + if (sizeInBytes > 0) + mediaDetails.addDetail(MediaDetails.INDEX_SIZE, sizeInBytes); + + MediaDetails.extractExifInfo(mediaDetails, path); + return mediaDetails; + } + @Override public int getLocalDataType(int dataID) { if (mPanoramaMetadata != null && mPanoramaMetadata.mUsePanoramaViewer) { @@ -338,8 +360,8 @@ public abstract class LocalMediaData implements LocalData { id = newData.id; title = newData.title; mimeType = newData.mimeType; - dateTaken = newData.dateTaken; - dateModified = newData.dateModified; + dateTakenInSeconds = newData.dateTakenInSeconds; + dateModifiedInSeconds = newData.dateModifiedInSeconds; path = newData.path; orientation = newData.orientation; width = newData.width; @@ -436,8 +458,8 @@ public abstract class LocalMediaData implements LocalData { d.id = c.getLong(COL_ID); d.title = c.getString(COL_TITLE); d.mimeType = c.getString(COL_MIME_TYPE); - d.dateTaken = c.getLong(COL_DATE_TAKEN); - d.dateModified = c.getLong(COL_DATE_MODIFIED); + d.dateTakenInSeconds = c.getLong(COL_DATE_TAKEN); + d.dateModifiedInSeconds = c.getLong(COL_DATE_MODIFIED); d.path = c.getString(COL_DATA); d.width = c.getInt(COL_WIDTH); d.height = c.getInt(COL_HEIGHT); @@ -475,7 +497,7 @@ public abstract class LocalMediaData implements LocalData { @Override public String toString() { return "Video:" + ",data=" + path + ",mimeType=" + mimeType - + "," + width + "x" + height + ",date=" + new Date(dateTaken); + + "," + width + "x" + height + ",date=" + new Date(dateTakenInSeconds); } @Override @@ -506,6 +528,12 @@ public abstract class LocalMediaData implements LocalData { return baseUri.buildUpon().appendPath(String.valueOf(id)).build(); } + @Override + public MediaDetails getMediaDetails(Context context) { + // TODO: Return valid MediaDetails for videos. + return new MediaDetails(); + } + @Override public int getLocalDataType(int dataID) { return LOCAL_VIDEO; @@ -525,8 +553,8 @@ public abstract class LocalMediaData implements LocalData { id = newData.id; title = newData.title; mimeType = newData.mimeType; - dateTaken = newData.dateTaken; - dateModified = newData.dateModified; + dateTakenInSeconds = newData.dateTakenInSeconds; + dateModifiedInSeconds = newData.dateModifiedInSeconds; path = newData.path; width = newData.width; height = newData.height; diff --git a/src/com/android/camera/data/MediaDetails.java b/src/com/android/camera/data/MediaDetails.java new file mode 100644 index 000000000..cb752733a --- /dev/null +++ b/src/com/android/camera/data/MediaDetails.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2013 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.camera.data; + +import android.util.Log; + +import com.android.camera2.R; +import com.android.gallery3d.exif.ExifInterface; +import com.android.gallery3d.exif.ExifTag; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.TreeMap; + +public class MediaDetails implements Iterable> { + @SuppressWarnings("unused") + private static final String TAG = "MediaDetails"; + + private TreeMap mDetails = new TreeMap(); + private HashMap mUnits = new HashMap(); + + public static final int INDEX_TITLE = 1; + public static final int INDEX_DESCRIPTION = 2; + public static final int INDEX_DATETIME = 3; + public static final int INDEX_LOCATION = 4; + public static final int INDEX_WIDTH = 5; + public static final int INDEX_HEIGHT = 6; + public static final int INDEX_ORIENTATION = 7; + public static final int INDEX_DURATION = 8; + public static final int INDEX_MIMETYPE = 9; + public static final int INDEX_SIZE = 10; + + // for EXIF + public static final int INDEX_MAKE = 100; + public static final int INDEX_MODEL = 101; + public static final int INDEX_FLASH = 102; + public static final int INDEX_FOCAL_LENGTH = 103; + public static final int INDEX_WHITE_BALANCE = 104; + public static final int INDEX_APERTURE = 105; + public static final int INDEX_SHUTTER_SPEED = 106; + public static final int INDEX_EXPOSURE_TIME = 107; + public static final int INDEX_ISO = 108; + + // Put this last because it may be long. + public static final int INDEX_PATH = 200; + + public static class FlashState { + private static int FLASH_FIRED_MASK = 1; + private static int FLASH_RETURN_MASK = 2 | 4; + private static int FLASH_MODE_MASK = 8 | 16; + private static int FLASH_FUNCTION_MASK = 32; + private static int FLASH_RED_EYE_MASK = 64; + private int mState; + + public FlashState(int state) { + mState = state; + } + + public boolean isFlashFired() { + return (mState & FLASH_FIRED_MASK) != 0; + } + } + + public void addDetail(int index, Object value) { + mDetails.put(index, value); + } + + public Object getDetail(int index) { + return mDetails.get(index); + } + + public int size() { + return mDetails.size(); + } + + @Override + public Iterator> iterator() { + return mDetails.entrySet().iterator(); + } + + public void setUnit(int index, int unit) { + mUnits.put(index, unit); + } + + public boolean hasUnit(int index) { + return mUnits.containsKey(index); + } + + public int getUnit(int index) { + return mUnits.get(index); + } + + private static void setExifData(MediaDetails details, ExifTag tag, + int key) { + if (tag != null) { + String value = null; + int type = tag.getDataType(); + if (type == ExifTag.TYPE_UNSIGNED_RATIONAL || type == ExifTag.TYPE_RATIONAL) { + value = String.valueOf(tag.getValueAsRational(0).toDouble()); + } else if (type == ExifTag.TYPE_ASCII) { + value = tag.getValueAsString(); + } else { + value = String.valueOf(tag.forceGetValueAsLong(0)); + } + if (key == MediaDetails.INDEX_FLASH) { + MediaDetails.FlashState state = new MediaDetails.FlashState( + Integer.valueOf(value.toString())); + details.addDetail(key, state); + } else { + details.addDetail(key, value); + } + } + } + + /** + * Extracts data from the EXIF of the given file and stores it in the + * MediaDetails instance. + */ + public static void extractExifInfo(MediaDetails details, String filePath) { + ExifInterface exif = new ExifInterface(); + try { + exif.readExif(filePath); + } catch (FileNotFoundException e) { + Log.w(TAG, "Could not find file to read exif: " + filePath, e); + } catch (IOException e) { + Log.w(TAG, "Could not read exif from file: " + filePath, e); + } + + setExifData(details, exif.getTag(ExifInterface.TAG_FLASH), + MediaDetails.INDEX_FLASH); + setExifData(details, exif.getTag(ExifInterface.TAG_IMAGE_WIDTH), + MediaDetails.INDEX_WIDTH); + setExifData(details, exif.getTag(ExifInterface.TAG_IMAGE_LENGTH), + MediaDetails.INDEX_HEIGHT); + setExifData(details, exif.getTag(ExifInterface.TAG_MAKE), + MediaDetails.INDEX_MAKE); + setExifData(details, exif.getTag(ExifInterface.TAG_MODEL), + MediaDetails.INDEX_MODEL); + setExifData(details, exif.getTag(ExifInterface.TAG_APERTURE_VALUE), + MediaDetails.INDEX_APERTURE); + setExifData(details, exif.getTag(ExifInterface.TAG_ISO_SPEED_RATINGS), + MediaDetails.INDEX_ISO); + setExifData(details, exif.getTag(ExifInterface.TAG_WHITE_BALANCE), + MediaDetails.INDEX_WHITE_BALANCE); + setExifData(details, exif.getTag(ExifInterface.TAG_EXPOSURE_TIME), + MediaDetails.INDEX_EXPOSURE_TIME); + ExifTag focalTag = exif.getTag(ExifInterface.TAG_FOCAL_LENGTH); + if (focalTag != null) { + details.addDetail(MediaDetails.INDEX_FOCAL_LENGTH, + focalTag.getValueAsRational(0).toDouble()); + details.setUnit(MediaDetails.INDEX_FOCAL_LENGTH, R.string.unit_mm); + } + } +} diff --git a/src/com/android/camera/data/SimpleViewData.java b/src/com/android/camera/data/SimpleViewData.java index d6fc1c416..8801599bb 100644 --- a/src/com/android/camera/data/SimpleViewData.java +++ b/src/com/android/camera/data/SimpleViewData.java @@ -145,4 +145,9 @@ public class SimpleViewData implements LocalData { public boolean canSwipeInFullScreen() { return true; } + + @Override + public MediaDetails getMediaDetails(Context context) { + return null; + } } diff --git a/src/com/android/camera/ui/DetailsDialog.java b/src/com/android/camera/ui/DetailsDialog.java new file mode 100644 index 000000000..cc0130d22 --- /dev/null +++ b/src/com/android/camera/ui/DetailsDialog.java @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2013 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.camera.ui; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.text.format.Formatter; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import com.android.camera.data.MediaDetails; +import com.android.camera2.R; + +import java.util.ArrayList; +import java.util.Map.Entry; + +/** + * Displays details (such as Exif) of a local media item. + */ +public class DetailsDialog { + + /** + * Creates a dialog for showing media data. + * + * @param context the Android context. + * @param mediaDetails the media details to display. + * @return A dialog that can be made visible to show the media details. + */ + public static Dialog create(Context context, MediaDetails mediaDetails) { + ListView detailsList = (ListView) LayoutInflater.from(context).inflate( + R.layout.details_list, null, false); + detailsList.setAdapter(new DetailsAdapter(context, mediaDetails)); + + final AlertDialog.Builder builder = + new AlertDialog.Builder(context); + return builder.setTitle(R.string.details).setView(detailsList) + .setPositiveButton(R.string.close, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + dialog.dismiss(); + } + }).create(); + } + + /** + * An adapter for feeding a details list view with the contents of a + * {@link MediaDetails} instance. + */ + private static class DetailsAdapter extends BaseAdapter { + private final Context mContext; + private final MediaDetails mMediaDetails; + private final ArrayList mItems; + private int mLocationIndex; + private int mWidthIndex = -1; + private int mHeightIndex = -1; + + public DetailsAdapter(Context context, MediaDetails details) { + mContext = context; + mMediaDetails = details; + mItems = new ArrayList(details.size()); + mLocationIndex = -1; + setDetails(context, details); + } + + private void setDetails(Context context, MediaDetails details) { + boolean resolutionIsValid = true; + String path = null; + for (Entry detail : details) { + String value; + switch (detail.getKey()) { + // TODO: Resolve address asynchronously. + case MediaDetails.INDEX_SIZE: { + value = Formatter.formatFileSize( + context, (Long) detail.getValue()); + break; + } + case MediaDetails.INDEX_WHITE_BALANCE: { + value = "1".equals(detail.getValue()) + ? context.getString(R.string.manual) + : context.getString(R.string.auto); + break; + } + case MediaDetails.INDEX_FLASH: { + MediaDetails.FlashState flash = + (MediaDetails.FlashState) detail.getValue(); + // TODO: camera doesn't fill in the complete values, + // show more information when it is fixed. + if (flash.isFlashFired()) { + value = context.getString(R.string.flash_on); + } else { + value = context.getString(R.string.flash_off); + } + break; + } + case MediaDetails.INDEX_EXPOSURE_TIME: { + value = (String) detail.getValue(); + double time = Double.valueOf(value); + if (time < 1.0f) { + value = String.format("1/%d", (int) (0.5f + 1 / time)); + } else { + int integer = (int) time; + time -= integer; + value = String.valueOf(integer) + "''"; + if (time > 0.0001) { + value += String.format(" 1/%d", (int) (0.5f + 1 / time)); + } + } + break; + } + case MediaDetails.INDEX_WIDTH: + mWidthIndex = mItems.size(); + value = detail.getValue().toString(); + if (value.equalsIgnoreCase("0")) { + value = context.getString(R.string.unknown); + resolutionIsValid = false; + } + break; + case MediaDetails.INDEX_HEIGHT: { + mHeightIndex = mItems.size(); + value = detail.getValue().toString(); + if (value.equalsIgnoreCase("0")) { + value = context.getString(R.string.unknown); + resolutionIsValid = false; + } + break; + } + case MediaDetails.INDEX_PATH: + // Get the path and then fall through to the default + // case + path = detail.getValue().toString(); + default: { + Object valueObj = detail.getValue(); + // This shouldn't happen, log its key to help us + // diagnose the problem. + if (valueObj == null) { + fail("%s's value is Null", + getDetailsName(context, + detail.getKey())); + } + value = valueObj.toString(); + } + } + int key = detail.getKey(); + if (details.hasUnit(key)) { + value = String.format("%s: %s %s", getDetailsName( + context, key), value, context.getString(details.getUnit(key))); + } else { + value = String.format("%s: %s", getDetailsName( + context, key), value); + } + mItems.add(value); + if (!resolutionIsValid) { + resolveResolution(path); + } + } + } + + public void resolveResolution(String path) { + Bitmap bitmap = BitmapFactory.decodeFile(path); + if (bitmap == null) + return; + onResolutionAvailable(bitmap.getWidth(), bitmap.getHeight()); + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public boolean isEnabled(int position) { + return false; + } + + @Override + public int getCount() { + return mItems.size(); + } + + @Override + public Object getItem(int position) { + return mMediaDetails.getDetail(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + TextView tv; + if (convertView == null) { + tv = (TextView) LayoutInflater.from(mContext).inflate( + R.layout.details, parent, false); + } else { + tv = (TextView) convertView; + } + tv.setText(mItems.get(position)); + return tv; + } + + public void onResolutionAvailable(int width, int height) { + if (width == 0 || height == 0) + return; + // Update the resolution with the new width and height + String widthString = String.format("%s: %d", + getDetailsName( + mContext, MediaDetails.INDEX_WIDTH), width); + String heightString = String.format("%s: %d", + getDetailsName( + mContext, MediaDetails.INDEX_HEIGHT), height); + mItems.set(mWidthIndex, String.valueOf(widthString)); + mItems.set(mHeightIndex, String.valueOf(heightString)); + notifyDataSetChanged(); + } + } + + public static String getDetailsName(Context context, int key) { + switch (key) { + case MediaDetails.INDEX_TITLE: + return context.getString(R.string.title); + case MediaDetails.INDEX_DESCRIPTION: + return context.getString(R.string.description); + case MediaDetails.INDEX_DATETIME: + return context.getString(R.string.time); + case MediaDetails.INDEX_LOCATION: + return context.getString(R.string.location); + case MediaDetails.INDEX_PATH: + return context.getString(R.string.path); + case MediaDetails.INDEX_WIDTH: + return context.getString(R.string.width); + case MediaDetails.INDEX_HEIGHT: + return context.getString(R.string.height); + case MediaDetails.INDEX_ORIENTATION: + return context.getString(R.string.orientation); + case MediaDetails.INDEX_DURATION: + return context.getString(R.string.duration); + case MediaDetails.INDEX_MIMETYPE: + return context.getString(R.string.mimetype); + case MediaDetails.INDEX_SIZE: + return context.getString(R.string.file_size); + case MediaDetails.INDEX_MAKE: + return context.getString(R.string.maker); + case MediaDetails.INDEX_MODEL: + return context.getString(R.string.model); + case MediaDetails.INDEX_FLASH: + return context.getString(R.string.flash); + case MediaDetails.INDEX_APERTURE: + return context.getString(R.string.aperture); + case MediaDetails.INDEX_FOCAL_LENGTH: + return context.getString(R.string.focal_length); + case MediaDetails.INDEX_WHITE_BALANCE: + return context.getString(R.string.white_balance); + case MediaDetails.INDEX_EXPOSURE_TIME: + return context.getString(R.string.exposure_time); + case MediaDetails.INDEX_ISO: + return context.getString(R.string.iso); + default: + return "Unknown key" + key; + } + } + + /** + * Throw an assertion error wit the given message. + * + * @param message the message, can contain placeholders. + * @param args if he message contains placeholders, these values will be + * used to fill them. + */ + private static void fail(String message, Object... args) { + throw new AssertionError( + args.length == 0 ? message : String.format(message, args)); + } +} -- cgit v1.2.3