Implent show-on-map functionality.
Also make sure the show-on-map item is only shown for items with coordinates. and add the coordinate to the details view.

  Bug: 10346208
  Bug: 10330505

Change-Id: Idaeec207bcc0e7311fa3b651868515ccea81d083
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index 98ea363..57863b3 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -215,8 +215,7 @@
                             hidePanoStitchingProgress();
                             return;
                         }
-                        int type = currentData.getLocalDataType(dataID);
-                        updateActionBarMenu(type);
+                        updateActionBarMenu(dataID);
 
                         Uri contentUri = currentData.getContentUri();
                         if (contentUri == null) {
@@ -249,9 +248,12 @@
     /**
      * According to the data type, make the menu items for supported operations
      * visible.
-     * @param type : the data type for the current local data.
+     * @param dataID the data ID of the current item.
      */
-    private void updateActionBarMenu(int type) {
+    private void updateActionBarMenu(int dataID) {
+        LocalData currentData = mDataAdapter.getLocalData(dataID);
+        int type = currentData.getLocalDataType();
+
         if (mActionBarMenu == null) {
             return;
         }
@@ -290,12 +292,14 @@
                 (supported & SUPPORT_MUTE) != 0);
         setMenuItemVisible(mActionBarMenu, R.id.action_setas,
                 (supported & SUPPORT_SETAS) != 0);
-        setMenuItemVisible(mActionBarMenu, R.id.action_show_on_map,
-                (supported & SUPPORT_SHOW_ON_MAP) != 0);
         setMenuItemVisible(mActionBarMenu, R.id.action_edit,
                 (supported & SUPPORT_EDIT) != 0);
         setMenuItemVisible(mActionBarMenu, R.id.action_details,
                 (supported & SUPPORT_INFO) != 0);
+
+        boolean itemHasLocation = currentData.getLatLong() != null;
+        setMenuItemVisible(mActionBarMenu, R.id.action_show_on_map,
+                itemHasLocation && (supported & SUPPORT_SHOW_ON_MAP) != 0);
     }
 
     private void setMenuItemVisible(Menu menu, int itemId, boolean visible) {
@@ -461,7 +465,10 @@
                 }).execute();
                 return true;
             case R.id.action_show_on_map:
-                // TODO: add the functionality.
+                double[] latLong = localData.getLatLong();
+                if (latLong != null) {
+                  CameraUtil.showOnMap(this, latLong);
+                }
                 return true;
             default:
                 return super.onOptionsItemSelected(item);
diff --git a/src/com/android/camera/data/CameraPreviewData.java b/src/com/android/camera/data/CameraPreviewData.java
index 3a45105..f6127e4 100644
--- a/src/com/android/camera/data/CameraPreviewData.java
+++ b/src/com/android/camera/data/CameraPreviewData.java
@@ -45,7 +45,7 @@
     }
 
     @Override
-    public int getLocalDataType(int dataID) {
+    public int getLocalDataType() {
         return LOCAL_CAMERA_PREVIEW;
     }
 
diff --git a/src/com/android/camera/data/LocalData.java b/src/com/android/camera/data/LocalData.java
index 61714e2..2b617d7 100644
--- a/src/com/android/camera/data/LocalData.java
+++ b/src/com/android/camera/data/LocalData.java
@@ -109,12 +109,11 @@
     /**
      * Returns the type of the local data defined by {@link LocalData}.
      *
-     * @param dataID The ID of the data.
      * @return The local data type. Could be one of the following:
      * {@code LOCAL_CAMERA_PREVIEW}, {@code LOCAL_VIEW}, {@code LOCAL_IMAGE},
      * {@code LOCAL_VIDEO}, and {@code LOCAL_PHOTO_SPHERE},
      */
-    int getLocalDataType(int dataID);
+    int getLocalDataType();
 
     /**
      * Refresh the data content.
diff --git a/src/com/android/camera/data/LocalMediaData.java b/src/com/android/camera/data/LocalMediaData.java
index e55274f..131c7e7 100644
--- a/src/com/android/camera/data/LocalMediaData.java
+++ b/src/com/android/camera/data/LocalMediaData.java
@@ -61,6 +61,8 @@
     protected int width;
     protected int height;
     protected long sizeInBytes;
+    protected double latitude;
+    protected double longitude;
 
     /** The panorama metadata information of this media data. */
     protected PhotoSphereHelper.PanoramaMetadata mPanoramaMetadata;
@@ -192,6 +194,16 @@
         }
     }
 
+    @Override
+    public double[] getLatLong() {
+        if (latitude == 0 && longitude == 0) {
+            return null;
+        }
+        return new double[] {
+                latitude, longitude
+        };
+    }
+
     protected boolean isUsing() {
         synchronized (mUsing) {
             return mUsing;
@@ -217,6 +229,8 @@
         public static final int COL_WIDTH = 7;
         public static final int COL_HEIGHT = 8;
         public static final int COL_SIZE = 9;
+        public static final int COL_LATITUDE = 10;
+        public static final int COL_LONGITUDE = 11;
 
         static final Uri CONTENT_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
 
@@ -226,16 +240,18 @@
          * These values should be kept in sync with column IDs (COL_*) above.
          */
         static final String[] QUERY_PROJECTION = {
-            MediaStore.Images.ImageColumns._ID,           // 0, int
-            MediaStore.Images.ImageColumns.TITLE,         // 1, string
-            MediaStore.Images.ImageColumns.MIME_TYPE,     // 2, string
-            MediaStore.Images.ImageColumns.DATE_TAKEN,    // 3, int
-            MediaStore.Images.ImageColumns.DATE_MODIFIED, // 4, int
-            MediaStore.Images.ImageColumns.DATA,          // 5, string
-            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
+            MediaStore.Images.ImageColumns._ID,           // 0,  int
+            MediaStore.Images.ImageColumns.TITLE,         // 1,  string
+            MediaStore.Images.ImageColumns.MIME_TYPE,     // 2,  string
+            MediaStore.Images.ImageColumns.DATE_TAKEN,    // 3,  int
+            MediaStore.Images.ImageColumns.DATE_MODIFIED, // 4,  int
+            MediaStore.Images.ImageColumns.DATA,          // 5,  string
+            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
+            MediaStore.Images.ImageColumns.LATITUDE,      // 10, double
+            MediaStore.Images.ImageColumns.LONGITUDE      // 11, double
         };
 
         private static final int mSupportedUIActions =
@@ -286,6 +302,8 @@
                 d.height = b;
             }
             d.sizeInBytes = c.getLong(COL_SIZE);
+            d.latitude = c.getDouble(COL_LATITUDE);
+            d.longitude = c.getDouble(COL_LONGITUDE);
             return d;
         }
 
@@ -338,11 +356,15 @@
                 mediaDetails.addDetail(MediaDetails.INDEX_SIZE, sizeInBytes);
 
             MediaDetails.extractExifInfo(mediaDetails, path);
+
+            if (latitude != 0 && longitude != 0) {
+              mediaDetails.addDetail(MediaDetails.INDEX_LOCATION, latitude + ", " + longitude);
+            }
             return mediaDetails;
         }
 
         @Override
-        public int getLocalDataType(int dataID) {
+        public int getLocalDataType() {
             if (mPanoramaMetadata != null && mPanoramaMetadata.mUsePanoramaViewer) {
                 return LOCAL_PHOTO_SPHERE;
             }
@@ -535,7 +557,7 @@
         }
 
         @Override
-        public int getLocalDataType(int dataID) {
+        public int getLocalDataType() {
             return LOCAL_VIDEO;
         }
 
diff --git a/src/com/android/camera/data/SimpleViewData.java b/src/com/android/camera/data/SimpleViewData.java
index 8801599..59d5f2c 100644
--- a/src/com/android/camera/data/SimpleViewData.java
+++ b/src/com/android/camera/data/SimpleViewData.java
@@ -86,7 +86,7 @@
     }
 
     @Override
-    public int getLocalDataType(int dataID) {
+    public int getLocalDataType() {
         return LOCAL_VIEW;
     }
 
@@ -150,4 +150,9 @@
     public MediaDetails getMediaDetails(Context context) {
         return null;
     }
+
+    @Override
+    public double[] getLatLong() {
+        return null;
+    }
 }
diff --git a/src/com/android/camera/ui/FilmStripView.java b/src/com/android/camera/ui/FilmStripView.java
index dd5c29e..5e6bf69 100644
--- a/src/com/android/camera/ui/FilmStripView.java
+++ b/src/com/android/camera/ui/FilmStripView.java
@@ -131,7 +131,6 @@
          */
         public int getWidth();
 
-
         /**
          * Returns the width of the image. The final layout of the view returned
          * by {@link DataAdapter#getView(android.content.Context, int)} will
@@ -145,6 +144,14 @@
         public int getViewType();
 
         /**
+         * Returns the coordinates of this item.
+         *
+         * @return A 2-element array containing {latitude, longitude}, or null,
+         *         if no position is known for this item.
+         */
+        public double[] getLatLong();
+
+        /**
          * Checks if the UI action is supported.
          *
          * @param action The UI actions to check.
diff --git a/src/com/android/camera/util/CameraUtil.java b/src/com/android/camera/util/CameraUtil.java
index a5d4161..c5dc71a 100644
--- a/src/com/android/camera/util/CameraUtil.java
+++ b/src/com/android/camera/util/CameraUtil.java
@@ -22,6 +22,7 @@
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.List;
+import java.util.Locale;
 import java.util.StringTokenizer;
 
 import android.annotation.TargetApi;
@@ -29,6 +30,7 @@
 import android.app.AlertDialog;
 import android.app.admin.DevicePolicyManager;
 import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -105,9 +107,13 @@
     public static final String SCENE_MODE_HDR = "hdr";
     public static final String TRUE = "true";
     public static final String FALSE = "false";
-    
-	/** Has to be in sync with the receiving MovieActivity. */
-	public static final String KEY_TREAT_UP_AS_BACK = "treat-up-as-back";
+
+    // Fields for the show-on-maps-functionality
+    private static final String MAPS_PACKAGE_NAME = "com.google.android.apps.maps";
+    private static final String MAPS_CLASS_NAME = "com.google.android.maps.MapsActivity";
+
+    /** Has to be in sync with the receiving MovieActivity. */
+    public static final String KEY_TREAT_UP_AS_BACK = "treat-up-as-back";
 
     public static boolean isSupported(String value, List<String> supported) {
         return supported == null ? false : supported.indexOf(value) >= 0;
@@ -832,4 +838,33 @@
                     Toast.LENGTH_SHORT).show();
         }
     }
+
+    /**
+     * Starts GMM with the given location shown. If this fails, and GMM could
+     * not be found, we use a geo intent as a fallback.
+     *
+     * @param context the Android context to use for starting the activities.
+     * @param latLong a 2-element array containing {latitude/longitude}.
+     */
+    public static void showOnMap(Context context, double[] latLong) {
+        try {
+            // We don't use "geo:latitude,longitude" because it only centers
+            // the MapView to the specified location, but we need a marker
+            // for further operations (routing to/from).
+            // The q=(lat, lng) syntax is suggested by geo-team.
+            String uri = String.format(Locale.ENGLISH, "http://maps.google.com/maps?f=q&q=(%f,%f)",
+                    latLong[0], latLong[1]);
+            ComponentName compName = new ComponentName(MAPS_PACKAGE_NAME,
+                    MAPS_CLASS_NAME);
+            Intent mapsIntent = new Intent(Intent.ACTION_VIEW,
+                    Uri.parse(uri)).setComponent(compName);
+            context.startActivity(mapsIntent);
+        } catch (ActivityNotFoundException e) {
+            // Use the "geo intent" if no GMM is installed
+            Log.e(TAG, "GMM activity not found!", e);
+            String url = String.format(Locale.ENGLISH, "geo:%f,%f", latLong[0], latLong[1]);
+            Intent mapsIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+            context.startActivity(mapsIntent);
+        }
+    }
 }