Add tests for unsupported MIME type usage

Apps sometimes use unsupported MIME type or empty/null MIME type. When
legacy apps use unsupported MIME type, even though we don't encourage
use of unsupported MIME type, we can't throw error to retain legacy
behavior. So, we try to guess the MIME type from file extension or from
the default MIME type of the given uri. Added tests to verify the same.

Bug: 157127219
Test: atest CtsScopedStorageHostTest#testInsertWithUnsupportedMimeType
Change-Id: I5dc51c6006fd8ec927b5af5630e22616c8c2c3e9
Merged-In: I5dc51c6006fd8ec927b5af5630e22616c8c2c3e9
(cherry picked from commit b8c2f87127a50a517be88f0bf5bffc22b5854fa7)
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java b/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
index 2144def..8dfe7b7 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
@@ -29,11 +29,10 @@
 import static android.scopedstorage.cts.lib.TestUtils.READDIR_QUERY;
 import static android.scopedstorage.cts.lib.TestUtils.SETATTR_QUERY;
 import static android.scopedstorage.cts.lib.TestUtils.canOpen;
-import static android.scopedstorage.cts.lib.TestUtils.getMediaContentUri;
+import static android.scopedstorage.cts.lib.TestUtils.getImageContentUri;
 
 import android.app.Activity;
 import android.content.Intent;
-import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.os.Bundle;
 import android.provider.MediaStore;
@@ -146,7 +145,7 @@
             values.put(MediaStore.Images.Media.RELATIVE_PATH, relativePath);
             values.put(MediaStore.Images.Media.DISPLAY_NAME, name);
 
-            getContentResolver().insert(getMediaContentUri(), values);
+            getContentResolver().insert(getImageContentUri(), values);
 
             final Intent intent = new Intent(queryType);
             intent.putExtra(queryType, true);
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
index cfb30a3..8729f9b 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
@@ -194,4 +194,9 @@
     public void testLegacyAppUpdatingOwnershipOfExistingEntry() throws Exception {
         runDeviceTest("testLegacyAppUpdatingOwnershipOfExistingEntry");
     }
+
+    @Test
+    public void testInsertWithUnsupportedMimeType() throws Exception {
+        runDeviceTest("testInsertWithUnsupportedMimeType");
+    }
 }
diff --git a/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java b/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
index f700391..2422f3b 100644
--- a/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
+++ b/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
@@ -33,9 +33,11 @@
 import static android.scopedstorage.cts.lib.TestUtils.getContentResolver;
 import static android.scopedstorage.cts.lib.TestUtils.getFileOwnerPackageFromDatabase;
 import static android.scopedstorage.cts.lib.TestUtils.getFileRowIdFromDatabase;
+import static android.scopedstorage.cts.lib.TestUtils.getImageContentUri;
 import static android.scopedstorage.cts.lib.TestUtils.installApp;
 import static android.scopedstorage.cts.lib.TestUtils.listAs;
 import static android.scopedstorage.cts.lib.TestUtils.openFileAs;
+import static android.scopedstorage.cts.lib.TestUtils.openWithMediaProvider;
 import static android.scopedstorage.cts.lib.TestUtils.pollForExternalStorageState;
 import static android.scopedstorage.cts.lib.TestUtils.pollForPermission;
 import static android.scopedstorage.cts.lib.TestUtils.setupDefaultDirectories;
@@ -55,11 +57,15 @@
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
 import android.provider.MediaStore;
 import android.scopedstorage.cts.lib.TestUtils;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
+import android.text.TextUtils;
 import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
@@ -78,6 +84,7 @@
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 
@@ -700,6 +707,57 @@
         }
     }
 
+    /**
+     * b/156717256,b/156336269: Test that MediaProvider doesn't throw error on usage of unsupported
+     * or empty/null MIME type.
+     */
+    @Test
+    public void testInsertWithUnsupportedMimeType() throws Exception {
+        pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, /*granted*/ true);
+        pollForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, /*granted*/ true);
+
+        final String IMAGE_FILE_DISPLAY_NAME = "LegacyStorageTest_file_" + NONCE;
+        final File imageFile = new File(TestUtils.getDcimDir(), IMAGE_FILE_DISPLAY_NAME + ".jpg");
+
+        for (String mimeType : new String[] {
+            "image/*", "", null, "foo/bar"
+        }) {
+            Uri uri = null;
+            try {
+                ContentValues values = new ContentValues();
+                values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
+                if (TextUtils.isEmpty(mimeType)) {
+                    values.put(MediaStore.MediaColumns.DISPLAY_NAME, imageFile.getName());
+                } else {
+                    values.put(MediaStore.MediaColumns.DISPLAY_NAME, IMAGE_FILE_DISPLAY_NAME);
+                }
+                values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
+
+                uri = getContentResolver().insert(getImageContentUri(), values, Bundle.EMPTY);
+                assertNotNull(uri);
+
+                try (final OutputStream fos = getContentResolver().openOutputStream(uri, "rw")) {
+                    fos.write(BYTES_DATA1);
+                }
+
+                // Closing the file should trigger a scan, we still scan again to ensure MIME type
+                // is extracted from file extension
+                assertNotNull(MediaStore.scanFile(getContentResolver(), imageFile));
+
+                final String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME,
+                        MediaStore.MediaColumns.MIME_TYPE};
+                try (Cursor c = getContentResolver().query(uri, projection, null, null, null)) {
+                    assertTrue(c.moveToFirst());
+                    assertEquals(c.getCount(), 1);
+                    assertEquals(c.getString(0), imageFile.getName());
+                    assertTrue("image/jpeg".equalsIgnoreCase(c.getString(1)));
+                }
+            } finally {
+                deleteWithMediaProviderNoThrow(uri);
+            }
+        }
+    }
+
     private static void assertCanCreateFile(File file) throws IOException {
         if (file.exists()) {
             file.delete();
diff --git a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
index f17cbbe..34fbe79 100644
--- a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
+++ b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
@@ -374,7 +374,7 @@
     /**
      * Returns the content URI for images based on the current storage volume.
      */
-    public static Uri getMediaContentUri() {
+    public static Uri getImageContentUri() {
         return MediaStore.Images.Media.getContentUri(sStorageVolumeName);
     }