summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/gallery3d/app/AlbumPage.java40
-rw-r--r--src/com/android/gallery3d/app/AlbumSetPage.java40
-rw-r--r--src/com/android/gallery3d/app/PhotoPage.java41
-rw-r--r--src/com/android/gallery3d/ui/DetailsAddressResolver.java116
-rw-r--r--src/com/android/gallery3d/ui/DetailsHelper.java144
-rw-r--r--src/com/android/gallery3d/ui/DialogDetailsView.java239
-rw-r--r--src/com/android/gallery3d/ui/GLDetailsView.java (renamed from src/com/android/gallery3d/ui/DetailsWindow.java)195
-rw-r--r--src/com/android/gallery3d/ui/ScrollView.java12
8 files changed, 603 insertions, 224 deletions
diff --git a/src/com/android/gallery3d/app/AlbumPage.java b/src/com/android/gallery3d/app/AlbumPage.java
index 1b6145f74..2f1c2955b 100644
--- a/src/com/android/gallery3d/app/AlbumPage.java
+++ b/src/com/android/gallery3d/app/AlbumPage.java
@@ -28,8 +28,8 @@ import com.android.gallery3d.data.Path;
import com.android.gallery3d.ui.ActionModeHandler;
import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener;
import com.android.gallery3d.ui.AlbumView;
-import com.android.gallery3d.ui.DetailsWindow;
-import com.android.gallery3d.ui.DetailsWindow.CloseListener;
+import com.android.gallery3d.ui.DetailsHelper;
+import com.android.gallery3d.ui.DetailsHelper.CloseListener;
import com.android.gallery3d.ui.GLCanvas;
import com.android.gallery3d.ui.GLView;
import com.android.gallery3d.ui.GridDrawer;
@@ -92,7 +92,8 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
private ActionMode mActionMode;
private ActionModeHandler mActionModeHandler;
private int mFocusIndex = 0;
- private DetailsWindow mDetailsWindow;
+ private DetailsHelper mDetailsHelper;
+ private MyDetailsSource mDetailsSource;
private MediaSet mMediaSet;
private boolean mShowDetails;
private float mUserDistance; // in pixel
@@ -115,13 +116,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
int slotViewRight = right - left;
if (mShowDetails) {
- mDetailsWindow.measure(
- MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- int width = mDetailsWindow.getMeasuredWidth();
- int detailLeft = right - left - width;
- slotViewRight = detailLeft;
- mDetailsWindow.layout(detailLeft, slotViewTop, detailLeft + width,
- bottom - top);
+ mDetailsHelper.layout(left, slotViewTop, right, bottom);
} else {
mAlbumView.setSelectionDrawer(mGridDrawer);
}
@@ -162,7 +157,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
}
if (mShowDetails) {
mHighlightDrawer.setHighlightItem(item.getPath());
- mDetailsWindow.reloadDetails(slotIndex);
+ mDetailsHelper.reloadDetails(slotIndex);
} else if (!mSelectionManager.inSelectionMode()) {
if (mGetContent) {
onGetContent(item);
@@ -221,6 +216,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
if (item == null) return;
mSelectionManager.setAutoLeaveSelectionMode(true);
mSelectionManager.toggle(item.getPath());
+ mDetailsSource.findIndex(slotIndex);
mAlbumView.invalidate();
}
}
@@ -263,6 +259,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
initializeData(data);
mGetContent = data.getBoolean(Gallery.KEY_GET_CONTENT, false);
mShowClusterMenu = data.getBoolean(KEY_SHOW_CLUSTER_MENU, false);
+ mDetailsSource = new MyDetailsSource();
startTransition(data);
@@ -328,9 +325,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
mIsActive = false;
mAlbumDataAdapter.pause();
mAlbumView.pause();
- if (mDetailsWindow != null) {
- mDetailsWindow.pause();
- }
+ DetailsHelper.pause();
Future<?> task = mPendingTask;
if (task != null) {
// cancel on going task
@@ -400,24 +395,23 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
private void showDetails() {
mShowDetails = true;
- if (mDetailsWindow == null) {
+ if (mDetailsHelper == null) {
mHighlightDrawer = new HighlightDrawer(mActivity.getAndroidContext());
- mDetailsWindow = new DetailsWindow(mActivity, new MyDetailsSource());
- mDetailsWindow.setCloseListener(new CloseListener() {
+ mDetailsHelper = new DetailsHelper(mActivity, mRootPane, mDetailsSource);
+ mDetailsHelper.setCloseListener(new CloseListener() {
public void onClose() {
hideDetails();
}
});
- mRootPane.addComponent(mDetailsWindow);
}
mAlbumView.setSelectionDrawer(mHighlightDrawer);
- mDetailsWindow.show();
+ mDetailsHelper.show();
}
private void hideDetails() {
mShowDetails = false;
mAlbumView.setSelectionDrawer(mGridDrawer);
- mDetailsWindow.hide();
+ mDetailsHelper.hide();
}
@Override
@@ -572,12 +566,16 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
}
}
- private class MyDetailsSource implements DetailsWindow.DetailsSource {
+ private class MyDetailsSource implements DetailsHelper.DetailsSource {
private int mIndex;
public int size() {
return mAlbumDataAdapter.size();
}
+ public int getIndex() {
+ return mIndex;
+ }
+
// If requested index is out of active window, suggest a valid index.
// If there is no valid index available, return -1.
public int findIndex(int indexHint) {
diff --git a/src/com/android/gallery3d/app/AlbumSetPage.java b/src/com/android/gallery3d/app/AlbumSetPage.java
index 73500c820..352cf5ad5 100644
--- a/src/com/android/gallery3d/app/AlbumSetPage.java
+++ b/src/com/android/gallery3d/app/AlbumSetPage.java
@@ -28,8 +28,8 @@ import com.android.gallery3d.settings.GallerySettings;
import com.android.gallery3d.ui.ActionModeHandler;
import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener;
import com.android.gallery3d.ui.AlbumSetView;
-import com.android.gallery3d.ui.DetailsWindow;
-import com.android.gallery3d.ui.DetailsWindow.CloseListener;
+import com.android.gallery3d.ui.DetailsHelper;
+import com.android.gallery3d.ui.DetailsHelper.CloseListener;
import com.android.gallery3d.ui.GLCanvas;
import com.android.gallery3d.ui.GLView;
import com.android.gallery3d.ui.GridDrawer;
@@ -88,7 +88,8 @@ public class AlbumSetPage extends ActivityState implements
private boolean mGetAlbum;
private ActionMode mActionMode;
private ActionModeHandler mActionModeHandler;
- private DetailsWindow mDetailsWindow;
+ private DetailsHelper mDetailsHelper;
+ private MyDetailsSource mDetailsSource;
private boolean mShowDetails;
private EyePosition mEyePosition;
@@ -114,13 +115,7 @@ public class AlbumSetPage extends ActivityState implements
int slotViewRight = right - left;
if (mShowDetails) {
- mDetailsWindow.measure(
- MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- int width = mDetailsWindow.getMeasuredWidth();
- int detailLeft = right - left - width;
- slotViewRight = detailLeft;
- mDetailsWindow.layout(detailLeft, slotViewTop, detailLeft + width,
- bottom - top);
+ mDetailsHelper.layout(left, slotViewTop, right, bottom);
} else {
mAlbumSetView.setSelectionDrawer(mGridDrawer);
}
@@ -182,7 +177,7 @@ public class AlbumSetPage extends ActivityState implements
if (mShowDetails) {
Path path = targetSet.getPath();
mHighlightDrawer.setHighlightItem(path);
- mDetailsWindow.reloadDetails(slotIndex);
+ mDetailsHelper.reloadDetails(slotIndex);
} else if (!mSelectionManager.inSelectionMode()) {
Bundle data = new Bundle(getData());
String mediaPath = targetSet.getPath().toString();
@@ -226,6 +221,7 @@ public class AlbumSetPage extends ActivityState implements
if (set == null) return;
mSelectionManager.setAutoLeaveSelectionMode(true);
mSelectionManager.toggle(set.getPath());
+ mDetailsSource.findIndex(slotIndex);
mAlbumSetView.invalidate();
}
}
@@ -274,6 +270,7 @@ public class AlbumSetPage extends ActivityState implements
mTitle = data.getString(AlbumSetPage.KEY_SET_TITLE);
mSubtitle = data.getString(AlbumSetPage.KEY_SET_SUBTITLE);
mEyePosition = new EyePosition(mActivity.getAndroidContext(), this);
+ mDetailsSource = new MyDetailsSource();
startTransition();
}
@@ -286,9 +283,7 @@ public class AlbumSetPage extends ActivityState implements
mAlbumSetDataAdapter.pause();
mAlbumSetView.pause();
mEyePosition.pause();
- if (mDetailsWindow != null) {
- mDetailsWindow.pause();
- }
+ DetailsHelper.pause();
GalleryActionBar actionBar = mActivity.getGalleryActionBar();
if (actionBar != null) actionBar.hideClusterTabs();
}
@@ -520,23 +515,22 @@ public class AlbumSetPage extends ActivityState implements
private void hideDetails() {
mShowDetails = false;
mAlbumSetView.setSelectionDrawer(mGridDrawer);
- mDetailsWindow.hide();
+ mDetailsHelper.hide();
}
private void showDetails() {
mShowDetails = true;
- if (mDetailsWindow == null) {
+ if (mDetailsHelper == null) {
mHighlightDrawer = new HighlightDrawer(mActivity.getAndroidContext());
- mDetailsWindow = new DetailsWindow(mActivity, new MyDetailsSource());
- mDetailsWindow.setCloseListener(new CloseListener() {
+ mDetailsHelper = new DetailsHelper(mActivity, mRootPane, mDetailsSource);
+ mDetailsHelper.setCloseListener(new CloseListener() {
public void onClose() {
hideDetails();
}
});
- mRootPane.addComponent(mDetailsWindow);
}
mAlbumSetView.setSelectionDrawer(mHighlightDrawer);
- mDetailsWindow.show();
+ mDetailsHelper.show();
}
private class MyLoadingListener implements LoadingListener {
@@ -557,12 +551,16 @@ public class AlbumSetPage extends ActivityState implements
}
}
- private class MyDetailsSource implements DetailsWindow.DetailsSource {
+ private class MyDetailsSource implements DetailsHelper.DetailsSource {
private int mIndex;
public int size() {
return mAlbumSetDataAdapter.size();
}
+ public int getIndex() {
+ return mIndex;
+ }
+
// If requested index is out of active window, suggest a valid index.
// If there is no valid index available, return -1.
public int findIndex(int indexHint) {
diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java
index f28eb221d..4fbffb55a 100644
--- a/src/com/android/gallery3d/app/PhotoPage.java
+++ b/src/com/android/gallery3d/app/PhotoPage.java
@@ -25,9 +25,9 @@ import com.android.gallery3d.data.MediaSet;
import com.android.gallery3d.data.MtpDevice;
import com.android.gallery3d.data.Path;
import com.android.gallery3d.picasasource.PicasaSource;
-import com.android.gallery3d.ui.DetailsWindow;
-import com.android.gallery3d.ui.DetailsWindow.CloseListener;
-import com.android.gallery3d.ui.DetailsWindow.DetailsSource;
+import com.android.gallery3d.ui.DetailsHelper;
+import com.android.gallery3d.ui.DetailsHelper.CloseListener;
+import com.android.gallery3d.ui.DetailsHelper.DetailsSource;
import com.android.gallery3d.ui.FilmStripView;
import com.android.gallery3d.ui.GLCanvas;
import com.android.gallery3d.ui.GLView;
@@ -82,7 +82,7 @@ public class PhotoPage extends ActivityState
private PhotoView mPhotoView;
private PhotoPage.Model mModel;
private FilmStripView mFilmStripView;
- private DetailsWindow mDetailsWindow;
+ private DetailsHelper mDetailsHelper;
private boolean mShowDetails;
// mMediaSet could be null if there is no KEY_MEDIA_SET_PATH supplied.
@@ -141,12 +141,8 @@ public class PhotoPage extends ActivityState
right - left, bottom - top);
}
if (mShowDetails) {
- mDetailsWindow.measure(
- MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- int width = mDetailsWindow.getMeasuredWidth();
- int viewTop = GalleryActionBar.getHeight((Activity) mActivity);
- mDetailsWindow.layout(
- 0, viewTop, width, bottom - top - filmStripHeight);
+ mDetailsHelper.layout(left, GalleryActionBar.getHeight((Activity) mActivity),
+ right, bottom);
}
}
};
@@ -257,7 +253,7 @@ public class PhotoPage extends ActivityState
if (mCurrentPhoto == null) return;
updateMenuOperations();
if (mShowDetails) {
- mDetailsWindow.reloadDetails(mModel.getCurrentIndex());
+ mDetailsHelper.reloadDetails(mModel.getCurrentIndex());
}
String title = photo.getName();
if (title != null) mActionBar.setTitle(title);
@@ -441,22 +437,21 @@ public class PhotoPage extends ActivityState
private void hideDetails() {
mShowDetails = false;
- mDetailsWindow.hide();
+ mDetailsHelper.hide();
}
private void showDetails(int index) {
mShowDetails = true;
- if (mDetailsWindow == null) {
- mDetailsWindow = new DetailsWindow(mActivity, new MyDetailsSource());
- mDetailsWindow.setCloseListener(new CloseListener() {
+ if (mDetailsHelper == null) {
+ mDetailsHelper = new DetailsHelper(mActivity, mRootPane, new MyDetailsSource());
+ mDetailsHelper.setCloseListener(new CloseListener() {
public void onClose() {
hideDetails();
}
});
- mRootPane.addComponent(mDetailsWindow);
}
- mDetailsWindow.reloadDetails(index);
- mDetailsWindow.show();
+ mDetailsHelper.reloadDetails(index);
+ mDetailsHelper.show();
}
public void onSingleTapUp(int x, int y) {
@@ -541,9 +536,7 @@ public class PhotoPage extends ActivityState
if (mFilmStripView != null) {
mFilmStripView.pause();
}
- if (mDetailsWindow != null) {
- mDetailsWindow.pause();
- }
+ DetailsHelper.pause();
mPhotoView.pause();
mModel.pause();
mHandler.removeMessages(MSG_HIDE_BARS);
@@ -568,6 +561,7 @@ public class PhotoPage extends ActivityState
}
private class MyDetailsSource implements DetailsSource {
+ private int mIndex;
public MediaDetails getDetails() {
return mModel.getCurrentMediaItem().getDetails();
}
@@ -575,7 +569,12 @@ public class PhotoPage extends ActivityState
return mMediaSet != null ? mMediaSet.getMediaItemCount() : 1;
}
public int findIndex(int indexHint) {
+ mIndex = indexHint;
return indexHint;
}
+
+ public int getIndex() {
+ return mIndex;
+ }
}
}
diff --git a/src/com/android/gallery3d/ui/DetailsAddressResolver.java b/src/com/android/gallery3d/ui/DetailsAddressResolver.java
new file mode 100644
index 000000000..fdf94ba09
--- /dev/null
+++ b/src/com/android/gallery3d/ui/DetailsAddressResolver.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2011 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.gallery3d.ui;
+
+import com.android.gallery3d.app.GalleryActivity;
+import com.android.gallery3d.data.MediaDetails;
+import com.android.gallery3d.util.Future;
+import com.android.gallery3d.util.FutureListener;
+import com.android.gallery3d.util.GalleryUtils;
+import com.android.gallery3d.util.ReverseGeocoder;
+import com.android.gallery3d.util.ThreadPool.Job;
+import com.android.gallery3d.util.ThreadPool.JobContext;
+
+import android.content.Context;
+import android.location.Address;
+import android.os.Handler;
+import android.os.Looper;
+
+public class DetailsAddressResolver {
+ private AddressResolvingListener mListener;
+ private double[] mLatlng;
+ private GalleryActivity mContext;
+ private Future<Address> mAddressLookupJob;
+ private Handler mHandler;
+
+ private class AddressLookupJob implements Job<Address> {
+
+ protected AddressLookupJob(double[] latlng) {
+ mLatlng = latlng;
+ }
+
+ public Address run(JobContext jc) {
+ ReverseGeocoder geocoder = new ReverseGeocoder(mContext.getAndroidContext());
+ return geocoder.lookupAddress(mLatlng[0], mLatlng[1], true);
+ }
+ }
+
+ public interface AddressResolvingListener {
+ public void onAddressAvailable(String address);
+ }
+
+ public DetailsAddressResolver(GalleryActivity context) {
+ mContext = context;
+ mHandler = new Handler(Looper.getMainLooper());
+ }
+
+ public String resolveAddress(double[] latlng, AddressResolvingListener listener) {
+ mLatlng = latlng;
+ mListener = listener;
+ mAddressLookupJob = mContext.getThreadPool().submit(
+ new AddressLookupJob(latlng),
+ new FutureListener<Address>() {
+ public void onFutureDone(final Future<Address> future) {
+ mAddressLookupJob = null;
+ if (!future.isCancelled()) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ updateLocation(future.get());
+ }
+ });
+ }
+ }
+ });
+ return GalleryUtils.formatLatitudeLongitude("(%f,%f)", mLatlng[0], mLatlng[1]);
+ }
+
+ private void updateLocation(Address address) {
+ if (address != null) {
+ Context context = mContext.getAndroidContext();
+ String parts[] = {
+ address.getAdminArea(),
+ address.getSubAdminArea(),
+ address.getLocality(),
+ address.getSubLocality(),
+ address.getThoroughfare(),
+ address.getSubThoroughfare(),
+ address.getPremises(),
+ address.getPostalCode(),
+ address.getCountryName()
+ };
+
+ String addressText = "";
+ for (int i = 0; i < parts.length; i++) {
+ if (parts[i] == null || parts[i].isEmpty()) continue;
+ if (!addressText.isEmpty()) {
+ addressText += ", ";
+ }
+ addressText += parts[i];
+ }
+ String text = String.format("%s : %s", DetailsHelper.getDetailsName(
+ context, MediaDetails.INDEX_LOCATION), addressText);
+ mListener.onAddressAvailable(text);
+ }
+ }
+
+ public void cancel() {
+ if (mAddressLookupJob != null) {
+ mAddressLookupJob.cancel();
+ mAddressLookupJob = null;
+ }
+ }
+}
diff --git a/src/com/android/gallery3d/ui/DetailsHelper.java b/src/com/android/gallery3d/ui/DetailsHelper.java
new file mode 100644
index 000000000..0ff01e6f3
--- /dev/null
+++ b/src/com/android/gallery3d/ui/DetailsHelper.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2010 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.gallery3d.ui;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.app.GalleryActivity;
+import com.android.gallery3d.data.MediaDetails;
+import com.android.gallery3d.ui.DetailsAddressResolver.AddressResolvingListener;
+
+import android.content.Context;
+import android.view.View.MeasureSpec;
+
+public class DetailsHelper {
+ private static DetailsAddressResolver sAddressResolver;
+ private DetailsViewContainer mContainer;
+
+ public interface DetailsSource {
+ public int size();
+ public int getIndex();
+ public int findIndex(int indexHint);
+ public MediaDetails getDetails();
+ }
+
+ public interface CloseListener {
+ public void onClose();
+ }
+
+ public interface DetailsViewContainer {
+ public void reloadDetails(int indexHint);
+ public void setCloseListener(CloseListener listener);
+ public void show();
+ public void hide();
+ }
+
+ public DetailsHelper(GalleryActivity activity, GLView rootPane, DetailsSource source) {
+ boolean useDialog = activity.getAndroidContext().getResources().getBoolean(
+ R.bool.dialog_details_view);
+ if (useDialog) {
+ mContainer = new DialogDetailsView(activity, source);
+ } else {
+ mContainer = new GLDetailsView(activity, source);
+ rootPane.addComponent((GLView) mContainer);
+ }
+ }
+
+ public void layout(int left, int top, int right, int bottom) {
+ if (mContainer instanceof GLView) {
+ GLView view = (GLView) mContainer;
+ view.measure(MeasureSpec.UNSPECIFIED,
+ MeasureSpec.makeMeasureSpec(bottom - top, MeasureSpec.AT_MOST));
+ view.layout(0, top, view.getMeasuredWidth(), top + view.getMeasuredHeight());
+ }
+ }
+
+ public void reloadDetails(int indexHint) {
+ mContainer.reloadDetails(indexHint);
+ }
+
+ public void setCloseListener(CloseListener listener) {
+ mContainer.setCloseListener(listener);
+ }
+
+ public static String resolveAddress(GalleryActivity activity, double[] latlng,
+ AddressResolvingListener listener) {
+ if (sAddressResolver == null) {
+ sAddressResolver = new DetailsAddressResolver(activity);
+ } else {
+ sAddressResolver.cancel();
+ }
+ return sAddressResolver.resolveAddress(latlng, listener);
+ }
+
+ public static void pause() {
+ if (sAddressResolver != null) sAddressResolver.cancel();
+ }
+
+ public void show() {
+ mContainer.show();
+ }
+
+ public void hide() {
+ mContainer.hide();
+ }
+
+ 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;
+ }
+ }
+}
+
+
diff --git a/src/com/android/gallery3d/ui/DialogDetailsView.java b/src/com/android/gallery3d/ui/DialogDetailsView.java
new file mode 100644
index 000000000..030bc34e8
--- /dev/null
+++ b/src/com/android/gallery3d/ui/DialogDetailsView.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2011 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.gallery3d.ui;
+
+import static com.android.gallery3d.ui.DetailsWindowConfig.FONT_SIZE;
+import static com.android.gallery3d.ui.DetailsWindowConfig.LEFT_RIGHT_EXTRA_PADDING;
+import static com.android.gallery3d.ui.DetailsWindowConfig.LINE_SPACING;
+import static com.android.gallery3d.ui.DetailsWindowConfig.PREFERRED_WIDTH;
+import static com.android.gallery3d.ui.DetailsWindowConfig.TOP_BOTTOM_EXTRA_PADDING;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.app.GalleryActivity;
+import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.data.MediaDetails;
+import com.android.gallery3d.ui.DetailsAddressResolver.AddressResolvingListener;
+import com.android.gallery3d.ui.DetailsHelper.CloseListener;
+import com.android.gallery3d.ui.DetailsHelper.DetailsViewContainer;
+import com.android.gallery3d.ui.DetailsHelper.DetailsSource;
+import com.android.gallery3d.util.Future;
+import com.android.gallery3d.util.FutureListener;
+import com.android.gallery3d.util.GalleryUtils;
+import com.android.gallery3d.util.ReverseGeocoder;
+import com.android.gallery3d.util.ThreadPool.Job;
+import com.android.gallery3d.util.ThreadPool.JobContext;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.database.DataSetObserver;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.location.Address;
+import android.os.Handler;
+import android.os.Message;
+import android.text.format.Formatter;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.MeasureSpec;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Map.Entry;
+
+public class DialogDetailsView implements DetailsViewContainer {
+ @SuppressWarnings("unused")
+ private static final String TAG = "DialogDetailsView";
+
+ private GalleryActivity mContext;
+ private DetailsAdapter mAdapter;
+ private MediaDetails mDetails;
+ private DetailsSource mSource;
+ private int mIndex;
+ private Dialog mDialog;
+ private int mLocationIndex;
+
+ public DialogDetailsView(GalleryActivity activity, DetailsSource source) {
+ mContext = activity;
+ mSource = source;
+ }
+
+ public void show() {
+ reloadDetails(mSource.getIndex());
+ mDialog.show();
+ }
+
+ public void hide() {
+ mDialog.hide();
+ }
+
+ public void reloadDetails(int indexHint) {
+ int index = mSource.findIndex(indexHint);
+ if (index == -1) return;
+ MediaDetails details = mSource.getDetails();
+ if (details != null) {
+ if (mIndex == index && mDetails == details) return;
+ mIndex = index;
+ mDetails = details;
+ setDetails(details);
+ }
+ }
+
+ public boolean isVisible() {
+ return mDialog.isShowing();
+ }
+
+ private void setDetails(MediaDetails details) {
+ mAdapter = new DetailsAdapter(details);
+ String title = String.format(
+ mContext.getAndroidContext().getString(R.string.details_title),
+ mIndex + 1, mSource.size());
+ mDialog = new AlertDialog.Builder((Activity) mContext)
+ .setAdapter(mAdapter, null)
+ .setTitle(title)
+ .setPositiveButton(R.string.close, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ mDialog.dismiss();
+ }
+ })
+ .create();
+ }
+
+ private class DetailsAdapter extends BaseAdapter implements AddressResolvingListener {
+ private ArrayList<String> mItems;
+
+ public DetailsAdapter(MediaDetails details) {
+ Context context = mContext.getAndroidContext();
+ mItems = new ArrayList<String>(details.size());
+ mLocationIndex = -1;
+ setDetails(context, details);
+ }
+
+ private void setDetails(Context context, MediaDetails details) {
+ for (Entry<Integer, Object> detail : details) {
+ String value;
+ switch (detail.getKey()) {
+ case MediaDetails.INDEX_LOCATION: {
+ double[] latlng = (double[]) detail.getValue();
+ mLocationIndex = mItems.size();
+ value = DetailsHelper.resolveAddress(mContext, latlng, mAdapter);
+ break;
+ }
+ 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;
+ }
+ default: {
+ Object valueObj = detail.getValue();
+ // This shouldn't happen, log its key to help us diagnose the problem.
+ Utils.assertTrue(valueObj != null, "%s's value is Null",
+ DetailsHelper.getDetailsName(context, detail.getKey()));
+ value = valueObj.toString();
+ }
+ }
+ int key = detail.getKey();
+ if (details.hasUnit(key)) {
+ value = String.format("%s : %s %s", DetailsHelper.getDetailsName(
+ context, key), value, context.getString(details.getUnit(key)));
+ } else {
+ value = String.format("%s : %s", DetailsHelper.getDetailsName(
+ context, key), value);
+ }
+ mItems.add(value);
+ }
+ }
+
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+
+ public boolean isEnabled(int position) {
+ return false;
+ }
+
+ public int getCount() {
+ return mItems.size();
+ }
+
+ public Object getItem(int position) {
+ return mDetails.getDetail(position);
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView tv;
+ if (convertView == null) {
+ tv = (TextView) LayoutInflater.from(mContext.getAndroidContext()).inflate(
+ R.layout.details, parent, false);
+ } else {
+ tv = (TextView) convertView;
+ }
+ tv.setText(mItems.get(position));
+ return tv;
+ }
+
+ public void onAddressAvailable(String address) {
+ mItems.set(mLocationIndex, address);
+ }
+ }
+
+ public void setCloseListener(CloseListener listener) {
+ }
+}
diff --git a/src/com/android/gallery3d/ui/DetailsWindow.java b/src/com/android/gallery3d/ui/GLDetailsView.java
index 760b73a91..cb98d4ee7 100644
--- a/src/com/android/gallery3d/ui/DetailsWindow.java
+++ b/src/com/android/gallery3d/ui/GLDetailsView.java
@@ -26,19 +26,14 @@ import com.android.gallery3d.R;
import com.android.gallery3d.app.GalleryActivity;
import com.android.gallery3d.common.Utils;
import com.android.gallery3d.data.MediaDetails;
-import com.android.gallery3d.util.Future;
-import com.android.gallery3d.util.FutureListener;
-import com.android.gallery3d.util.GalleryUtils;
-import com.android.gallery3d.util.ReverseGeocoder;
-import com.android.gallery3d.util.ThreadPool.Job;
-import com.android.gallery3d.util.ThreadPool.JobContext;
+import com.android.gallery3d.ui.DetailsAddressResolver.AddressResolvingListener;
+import com.android.gallery3d.ui.DetailsHelper.DetailsSource;
+import com.android.gallery3d.ui.DetailsHelper.DetailsViewContainer;
+import com.android.gallery3d.ui.DetailsHelper.CloseListener;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
-import android.location.Address;
-import android.os.Handler;
-import android.os.Message;
import android.text.format.Formatter;
import android.view.MotionEvent;
import android.view.View.MeasureSpec;
@@ -46,11 +41,9 @@ import android.view.View.MeasureSpec;
import java.util.ArrayList;
import java.util.Map.Entry;
-// TODO: Add scroll bar to this window.
-public class DetailsWindow extends GLView {
+public class GLDetailsView extends GLView implements DetailsViewContainer {
@SuppressWarnings("unused")
- private static final String TAG = "DetailsWindow";
- private static final int MSG_REFRESH_LOCATION = 1;
+ private static final String TAG = "GLDetailsView";
private static final int FONT_COLOR = Color.WHITE;
private static final int CLOSE_BUTTON_SIZE = 32;
@@ -62,8 +55,6 @@ public class DetailsWindow extends GLView {
private DetailsSource mSource;
private int mIndex;
private int mLocationIndex;
- private Future<Address> mAddressLookupJob;
- private Handler mHandler;
private Icon mCloseButton;
private int mMaxDetailLength;
private CloseListener mListener;
@@ -71,32 +62,12 @@ public class DetailsWindow extends GLView {
private ScrollView mScrollView;
private DetailsPanel mDetailPanel = new DetailsPanel();
- public interface DetailsSource {
- public int size();
- public int findIndex(int indexHint);
- public MediaDetails getDetails();
- }
-
- public interface CloseListener {
- public void onClose();
- }
-
- public DetailsWindow(GalleryActivity activity, DetailsSource source) {
+ public GLDetailsView(GalleryActivity activity, DetailsSource source) {
mContext = activity;
mSource = source;
- mHandler = new SynchronizedHandler(activity.getGLRoot()) {
- @Override
- public void handleMessage(Message msg) {
- switch(msg.what) {
- case MSG_REFRESH_LOCATION:
- mModel.updateLocation((Address) msg.obj);
- invalidate();
- break;
- }
- }
- };
+
Context context = activity.getAndroidContext();
- ResourceTexture icon = new ResourceTexture(context, R.drawable.ic_menu_cancel_holo_light);
+ ResourceTexture icon = new ResourceTexture(context, R.drawable.ic_lockscreen_chevron_up);
setBackground(new NinePatchTexture(context, R.drawable.popup_full_dark));
mCloseButton = new Icon(context, icon, CLOSE_BUTTON_SIZE, CLOSE_BUTTON_SIZE) {
@@ -114,8 +85,6 @@ public class DetailsWindow extends GLView {
super.addComponent(mScrollView);
super.addComponent(mCloseButton);
-
- reloadDetails(0);
}
public void setCloseListener(CloseListener listener) {
@@ -162,15 +131,16 @@ public class DetailsWindow extends GLView {
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
- int height = MeasureSpec.getSize(heightSpec);
+ mScrollView.measure(widthSpec, heightSpec);
+ mCloseButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ int height = mScrollView.getMeasuredHeight() + mCloseButton.getMeasuredHeight();
MeasureHelper.getInstance(this)
- .setPreferredContentSize(PREFERRED_WIDTH, height)
+ .setPreferredContentSize(mScrollView.getMeasuredWidth(), height)
.measure(widthSpec, heightSpec);
}
@Override
protected void onLayout(boolean sizeChange, int l, int t, int r, int b) {
- mCloseButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int bWidth = mCloseButton.getMeasuredWidth();
int bHeight = mCloseButton.getMeasuredHeight();
int width = getWidth();
@@ -184,6 +154,7 @@ public class DetailsWindow extends GLView {
}
public void show() {
+ reloadDetails(mSource.getIndex());
setVisibility(GLView.VISIBLE);
requestLayout();
}
@@ -193,14 +164,6 @@ public class DetailsWindow extends GLView {
requestLayout();
}
- public void pause() {
- Future<Address> lookupJob = mAddressLookupJob;
- if (lookupJob != null) {
- lookupJob.cancel();
- lookupJob.waitDone();
- }
- }
-
public void reloadDetails(int indexHint) {
int index = mSource.findIndex(indexHint);
if (index == -1) return;
@@ -219,19 +182,7 @@ public class DetailsWindow extends GLView {
invalidate();
}
- private class AddressLookupJob implements Job<Address> {
- double[] mLatlng;
- protected AddressLookupJob(double[] latlng) {
- mLatlng = latlng;
- }
-
- public Address run(JobContext jc) {
- ReverseGeocoder geocoder = new ReverseGeocoder(mContext.getAndroidContext());
- return geocoder.lookupAddress(mLatlng[0], mLatlng[1], true);
- }
- }
-
- private class MyDataModel {
+ private class MyDataModel implements AddressResolvingListener {
ArrayList<Texture> mItems;
public MyDataModel(MediaDetails details) {
@@ -248,7 +199,9 @@ public class DetailsWindow extends GLView {
String value;
switch (detail.getKey()) {
case MediaDetails.INDEX_LOCATION: {
- value = getLocationText((double[]) detail.getValue());
+ double[] latlng = (double[]) detail.getValue();
+ mLocationIndex = mItems.size();
+ value = DetailsHelper.resolveAddress(mContext, latlng, this);
break;
}
case MediaDetails.INDEX_SIZE: {
@@ -293,16 +246,17 @@ public class DetailsWindow extends GLView {
Object valueObj = detail.getValue();
// This shouldn't happen, log its key to help us diagnose the problem.
Utils.assertTrue(valueObj != null, "%s's value is Null",
- getName(context, detail.getKey()));
+ DetailsHelper.getDetailsName(context, detail.getKey()));
value = valueObj.toString();
}
}
int key = detail.getKey();
if (details.hasUnit(key)) {
- value = String.format("%s : %s %s", getName(context, key), value,
- context.getString(details.getUnit(key)));
+ value = String.format("%s : %s %s", DetailsHelper.getDetailsName(
+ context, key), value, context.getString(details.getUnit(key)));
} else {
- value = String.format("%s : %s", getName(context, key), value);
+ value = String.format("%s : %s", DetailsHelper.getDetailsName(
+ context, key), value);
}
Texture label = MultiLineTexture.newInstance(
value, mMaxDetailLength, FONT_SIZE, FONT_COLOR);
@@ -310,54 +264,6 @@ public class DetailsWindow extends GLView {
}
}
- private String getLocationText(double[] latlng) {
- String text = GalleryUtils.formatLatitudeLongitude("(%f,%f)", latlng[0], latlng[1]);
- mAddressLookupJob = mContext.getThreadPool().submit(
- new AddressLookupJob(latlng),
- new FutureListener<Address>() {
- public void onFutureDone(Future<Address> future) {
- mAddressLookupJob = null;
- if (!future.isCancelled()) {
- mHandler.sendMessage(mHandler.obtainMessage(
- MSG_REFRESH_LOCATION, future.get()));
- }
- }
- });
- mLocationIndex = mItems.size();
- return text;
- }
-
- public void updateLocation(Address address) {
- int index = mLocationIndex;
- if (address != null && index >=0 && index < mItems.size()) {
- Context context = mContext.getAndroidContext();
- String parts[] = {
- address.getAdminArea(),
- address.getSubAdminArea(),
- address.getLocality(),
- address.getSubLocality(),
- address.getThoroughfare(),
- address.getSubThoroughfare(),
- address.getPremises(),
- address.getPostalCode(),
- address.getCountryName()
- };
-
- String addressText = "";
- for (int i = 0; i < parts.length; i++) {
- if (parts[i] == null || parts[i].isEmpty()) continue;
- if (!addressText.isEmpty()) {
- addressText += ", ";
- }
- addressText += parts[i];
- }
- String text = String.format("%s : %s", getName(context,
- MediaDetails.INDEX_LOCATION), addressText);
- mItems.set(index, MultiLineTexture.newInstance(
- text, mMaxDetailLength, FONT_SIZE, FONT_COLOR));
- }
- }
-
public Texture getView(int index) {
return mItems.get(index);
}
@@ -365,50 +271,11 @@ public class DetailsWindow extends GLView {
public int size() {
return mItems.size();
}
- }
- private static String getName(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;
+ public void onAddressAvailable(String address) {
+ mItems.set(mLocationIndex, MultiLineTexture.newInstance(
+ address, mMaxDetailLength, FONT_SIZE, FONT_COLOR));
+ GLDetailsView.this.invalidate();
}
}
@@ -423,10 +290,12 @@ public class DetailsWindow extends GLView {
return;
}
- int h = getPaddings().top + LINE_SPACING;
+ Rect p = getPaddings();
+ int h = p.top + LINE_SPACING;
for (int i = 0, n = mModel.size(); i < n; ++i) {
h += mModel.getView(i).getHeight() + LINE_SPACING;
}
+ h += p.bottom;
MeasureHelper.getInstance(this)
.setPreferredContentSize(PREFERRED_WIDTH, h)
@@ -449,4 +318,8 @@ public class DetailsWindow extends GLView {
}
}
}
+
+ public GLView getGLView() {
+ return this;
+ }
}
diff --git a/src/com/android/gallery3d/ui/ScrollView.java b/src/com/android/gallery3d/ui/ScrollView.java
index f7628335c..23a8bb5bf 100644
--- a/src/com/android/gallery3d/ui/ScrollView.java
+++ b/src/com/android/gallery3d/ui/ScrollView.java
@@ -44,6 +44,18 @@ public class ScrollView extends GLView {
}
@Override
+ protected void onMeasure(int widthSpec, int heightSpec) {
+ GLView view = getContentView();
+ if (view != null) {
+ view.measure(widthSpec, heightSpec);
+ MeasureHelper.getInstance(this)
+ .setPreferredContentSize(view.getMeasuredWidth(),
+ view.getMeasuredHeight())
+ .measure(widthSpec, heightSpec);
+ }
+ }
+
+ @Override
public void onLayout(boolean sizeChange, int l, int t, int r, int b) {
GLView content = getContentView();
int width = getWidth();