Merge "CtsVerifier: Modify camera intents test to test for exif and location of image" am: 4ad716fdca am: 56e7e5341c am: c7b54cb36e

Change-Id: I9c15c6fb37f762dbe6e70c1739a78755f2fb1b9b
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/intents/CameraIntentsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/intents/CameraIntentsActivity.java
index 2757237..b7a80de 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/intents/CameraIntentsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/intents/CameraIntentsActivity.java
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PermissionInfo;
 import android.hardware.Camera;
+import android.media.ExifInterface;
 import android.media.MediaMetadataRetriever;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -51,6 +52,8 @@
 import static android.media.MediaMetadataRetriever.METADATA_KEY_LOCATION;
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.util.TreeSet;
 import java.util.Date;
 import java.text.SimpleDateFormat;
@@ -103,7 +106,8 @@
     private ImageButton mFailButton;
     private Button mStartTestButton;
     private Button mSettingsButton;
-    private File mVideoTargetDir = null;
+    private File mDebugFolder = null;
+    private File mImageTarget = null;
     private File mVideoTarget = null;
     private int mState = STATE_OFF;
     // MediaStore.Images.Media.EXTERNAL_CONTENT_URI or
@@ -420,49 +424,90 @@
             mActivityResult = true;
             synchronized(mLock) {
                 if (mState != STATE_FAILED) {
-                    /**
-                     * For images, we don't need to do more checks, since location in image exif is
-                     * checked by cts test: MediaStoreUiTest .
-                     */
-                    if (stageIndex == STAGE_INTENT_PICTURE) {
-                        mActionSuccess = true;
-                        // Set UriSuccess to true to avoid long wait in WaitForTriggerTask
-                        mUriSuccess = true;
-                        updateSuccessState();
-                        return;
+                    switch (stageIndex) {
+                        case STAGE_INTENT_PICTURE:
+                            handleIntentPictureResult();
+                            break;
+                        case STAGE_INTENT_VIDEO:
+                            handleIntentVideoResult();
+                            break;
+                        default:
+                            return;
                     }
-                    if (stageIndex != STAGE_INTENT_VIDEO) {
-                        return;
-                    }
-
-                    if (mVideoTarget == null) {
-                        Log.d(TAG, "Video target was not set");
-                        return;
-                    }
-                    /**
-                     * Check that there is no location data in video.
-                     */
-                    MediaMetadataRetriever mediaRetriever = new MediaMetadataRetriever();
-                    mediaRetriever.setDataSource(mVideoTarget.toString());
-                    if (mediaRetriever.extractMetadata(METADATA_KEY_HAS_VIDEO) == null ||
-                        mediaRetriever.extractMetadata(METADATA_KEY_LOCATION) != null) {
-                        mState = STATE_FAILED;
-                    } else {
-                        mVideoTarget.delete();
-                    }
-                    Log.d(TAG, "METADATA_KEY_HAS_VIDEO: " +
-                            mediaRetriever.extractMetadata(METADATA_KEY_HAS_VIDEO) +
-                            " METADATA_KEY_LOCATION: " +
-                            mediaRetriever.extractMetadata(METADATA_KEY_LOCATION));
-                    mediaRetriever.release();
-                    /* successful, unless we get the URI trigger back
-                     at some point later on */
-                    mActionSuccess = true;
                 }
             }
         }
     }
 
+    private void handleIntentPictureResult() {
+        if (mImageTarget == null) {
+            Log.d(TAG, "Image target was not set");
+            return;
+        }
+        try {
+            if (!mImageTarget.exists() || mImageTarget.length() <= 65536) {
+                Log.d(TAG, "Image target does not exist or it is too small");
+                mState = STATE_FAILED;
+                return;
+            }
+
+            try {
+                final ExifInterface exif = new ExifInterface(new FileInputStream(mImageTarget));
+                if (!checkExifAttribute(exif, ExifInterface.TAG_MAKE)
+                    || !checkExifAttribute(exif, ExifInterface.TAG_MODEL)
+                    || !checkExifAttribute(exif, ExifInterface.TAG_DATETIME)) {
+                    Log.d(TAG, "The required tag does not appear in the exif");
+                    mState = STATE_FAILED;
+                    return;
+                }
+
+                float[] latLong = new float[2];
+                if (exif.getLatLong(latLong)) {
+                    Log.d(TAG, "Should not contain location information");
+                    mState = STATE_FAILED;
+                    return;
+                }
+                mActionSuccess = true;
+            } catch (IOException ex) {
+                Log.e(TAG, "Failed to verify Exif", ex);
+                mState = STATE_FAILED;
+                return;
+            }
+        } finally {
+            mImageTarget.delete();
+        }
+    }
+
+    private void handleIntentVideoResult() {
+        if (mVideoTarget == null) {
+            Log.d(TAG, "Video target was not set");
+            return;
+        }
+        /**
+         * Check that there is no location data in video.
+         */
+        MediaMetadataRetriever mediaRetriever = new MediaMetadataRetriever();
+        mediaRetriever.setDataSource(mVideoTarget.toString());
+        if (mediaRetriever.extractMetadata(METADATA_KEY_HAS_VIDEO) == null ||
+            mediaRetriever.extractMetadata(METADATA_KEY_LOCATION) != null) {
+            mState = STATE_FAILED;
+        } else {
+            mVideoTarget.delete();
+        }
+        Log.d(TAG, "METADATA_KEY_HAS_VIDEO: " +
+              mediaRetriever.extractMetadata(METADATA_KEY_HAS_VIDEO) +
+              " METADATA_KEY_LOCATION: " +
+              mediaRetriever.extractMetadata(METADATA_KEY_LOCATION));
+        mediaRetriever.release();
+        /* successful, unless we get the URI trigger back at some point later on. */
+        mActionSuccess = true;
+    }
+
+    private boolean checkExifAttribute(ExifInterface exif, String tag) {
+        final String res = exif.getAttribute(tag);
+        return res != null && res.length() > 0;
+    }
+
     @Override
     public String getTestDetails() {
         return mReportBuilder.toString();
@@ -549,7 +594,7 @@
              * Video intents do not need to wait on a ContentProvider broadcast since we're starting
              * the intent activity with EXTRA_OUTPUT set
              */
-            if (stageIndex != STAGE_INTENT_VIDEO) {
+            if (stageIndex != STAGE_INTENT_VIDEO && stageIndex != STAGE_INTENT_PICTURE) {
                 JobInfo job = makeJobInfo(TEST_JOB_TYPES[stageIndex]);
                 jobScheduler.schedule(job);
                 new WaitForTriggerTask().execute();
@@ -575,21 +620,33 @@
 
             if (intentStr != null) {
                 cameraIntent = new Intent(intentStr);
-                if (stageIndex == STAGE_INTENT_VIDEO) {
-                    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
-                    mVideoTargetDir = new File(this.getFilesDir(), "debug");
-                    mVideoTarget = new File(mVideoTargetDir, timeStamp  + "video.mp4");
-                    mVideoTargetDir.mkdirs();
-                    if (!mVideoTargetDir.exists()) {
-                        Toast.makeText(this, R.string.ci_directory_creation_error,
-                                Toast.LENGTH_SHORT).show();
-                        Log.v(TAG, "Could not create directory");
-                        return;
-                    }
-                    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(this,
-                              "com.android.cts.verifier.managedprovisioning.fileprovider",
-                              mVideoTarget));
+                mDebugFolder = new File(this.getFilesDir(), "debug");
+                mDebugFolder.mkdirs();
+                if (!mDebugFolder.exists()) {
+                    Toast.makeText(this, R.string.ci_directory_creation_error,
+                            Toast.LENGTH_SHORT).show();
+                    Log.v(TAG, "Could not create directory");
+                    return;
                 }
+
+                File targetFile;
+                String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+                switch (stageIndex) {
+                    case STAGE_INTENT_PICTURE:
+                        mImageTarget = new File(mDebugFolder, timeStamp + "capture.jpg");
+                        targetFile = mImageTarget;
+                        break;
+                    case STAGE_INTENT_VIDEO:
+                        mVideoTarget = new File(mDebugFolder, timeStamp  + "video.mp4");
+                        targetFile = mVideoTarget;
+                        break;
+                    default:
+                        Log.wtf(TAG, "Unexpected stage index to send intent with extras");
+                        return;
+                }
+                cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(this,
+                              "com.android.cts.verifier.managedprovisioning.fileprovider",
+                              targetFile));
                 startActivityForResult(cameraIntent, 1337 + getStageIndex());
             }