Camera2: Plumb exif data to intent results

Bug: 130181094

Test: Install Camera2; runtest -x MediaStoreUiTest.java; adb pull debug images and
      verify that exif exists.

Change-Id: I37a4936e331e989e9a6a0d05efc82fe90806dbe7
Signed-off-by: Jayant Chowdhary <jchowdhary@google.com>
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index 352fa38..8c0b5bf 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -29,6 +29,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
@@ -158,6 +159,7 @@
 import com.bumptech.glide.MemoryCategory;
 import com.bumptech.glide.load.DecodeFormat;
 import com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor;
+import com.android.camera.exif.ExifInterface;
 
 import com.google.common.base.Optional;
 import com.google.common.logging.eventprotos;
@@ -1433,7 +1435,7 @@
         mOnCreateTime = System.currentTimeMillis();
         mAppContext = getApplicationContext();
         mMainHandler = new MainHandler(this, getMainLooper());
-        mLocationManager = new LocationManager(mAppContext);
+        mLocationManager = new LocationManager(mAppContext, shouldUseNoOpLocation());
         mOrientationManager = new OrientationManagerImpl(this, mMainHandler);
         mSettingsManager = getServices().getSettingsManager();
         mSoundPlayer = new SoundPlayer(mAppContext);
@@ -1731,6 +1733,35 @@
     }
 
     /**
+     * Incase the calling package doesn't have ACCESS_FINE_LOCATION permissions, we should not pass
+     * it valid location information in exif.
+     */
+    private boolean shouldUseNoOpLocation () {
+        String callingPackage = getCallingPackage();
+        if (callingPackage == null) {
+            // Activity not started through startActivityForResult.
+            return false;
+        }
+        PackageInfo packageInfo = null;
+        try {
+            packageInfo = getPackageManager().getPackageInfo(callingPackage,
+                    PackageManager.GET_PERMISSIONS);
+        } catch (Exception e) {
+            Log.w(TAG, "Unable to get PackageInfo for callingPackage " + callingPackage);
+        }
+        if (packageInfo != null) {
+            for (int i = 0; i < packageInfo.requestedPermissions.length; i++) {
+                if (packageInfo.requestedPermissions[i].equals(
+                        Manifest.permission.ACCESS_FINE_LOCATION) &&
+                        (packageInfo.requestedPermissionsFlags[i] &
+                        PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
+                  return false;
+                }
+            }
+        }
+        return true;
+    }
+    /**
      * Call this whenever the mode drawer or filmstrip change the visibility
      * state.
      */
diff --git a/src/com/android/camera/app/NoOpLocationProvider.java b/src/com/android/camera/app/NoOpLocationProvider.java
new file mode 100644
index 0000000..1cdbda3
--- /dev/null
+++ b/src/com/android/camera/app/NoOpLocationProvider.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 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.app;
+
+import android.content.Context;
+import android.location.Location;
+
+/**
+ * Dummy Location provider to be used when location information shouldn't be provided to the client.
+ */
+public class NoOpLocationProvider implements LocationProvider {
+
+    public NoOpLocationProvider(Context context) {
+    }
+
+    @Override
+    public Location getCurrentLocation() {
+        return null;
+    }
+
+    @Override
+    public void recordLocation(boolean recordLocation) {
+    }
+
+    @Override
+    public void disconnect() {
+    }
+}
diff --git a/src/com/android/camera/captureintent/CaptureIntentSession.java b/src/com/android/camera/captureintent/CaptureIntentSession.java
index 6fb22c6..bdc0ea8 100644
--- a/src/com/android/camera/captureintent/CaptureIntentSession.java
+++ b/src/com/android/camera/captureintent/CaptureIntentSession.java
@@ -33,6 +33,8 @@
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import javax.annotation.Nonnull;
 
 /**
@@ -149,7 +151,15 @@
     @Override
     public synchronized ListenableFuture<Optional<Uri>> saveAndFinish(byte[] data, int width,
             int height, int orientation, ExifInterface exif) {
-        mSessionNotifier.notifySessionPictureDataAvailable(data, orientation);
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        try {
+            exif.writeExif(data, byteArrayOutputStream);
+        } catch (IOException e) {
+            Log.e(TAG, "exception while trying to append exif to jpeg data");
+        }
+        byte[] dataWithExif = byteArrayOutputStream.toByteArray();
+        //No need to close byteArrayOutputStream since that has no effect.
+        mSessionNotifier.notifySessionPictureDataAvailable(dataWithExif, orientation);
         return Futures.immediateFuture(Optional.<Uri> absent());
     }
 
diff --git a/src_pd/com/android/camera/app/LocationManager.java b/src_pd/com/android/camera/app/LocationManager.java
index 6a3440b..90839b0 100644
--- a/src_pd/com/android/camera/app/LocationManager.java
+++ b/src_pd/com/android/camera/app/LocationManager.java
@@ -31,10 +31,12 @@
     LocationProvider mLocationProvider;
     private boolean mRecordLocation;
 
-    public LocationManager(Context context) {
-        Log.d(TAG, "Using legacy location provider.");
-        LegacyLocationProvider llp = new LegacyLocationProvider(context);
-        mLocationProvider = llp;
+    public LocationManager(Context context, boolean NoOpLocationProvider) {
+        Log.d(TAG, "Using " +
+                (NoOpLocationProvider ? "NoOpLocationProvider" : "LegacyLocationProvider"));
+        LocationProvider lp = NoOpLocationProvider ? new NoOpLocationProvider(context) :
+                new LegacyLocationProvider(context);
+        mLocationProvider = lp;
     }
 
     /**