am 81c1ef94: Merge "Add bionic unit tests to CTS."

* commit '81c1ef94541a4cb44a9738b048a79fbc3ebd5e3f':
  Add bionic unit tests to CTS.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
index afbf97e..46963a0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
@@ -172,6 +172,14 @@
             new Feature(PackageManager.FEATURE_TELEVISION, false),
     };
 
+    public static final Feature[] ALL_JELLY_BEAN_MR2_FEATURES = {
+            new Feature("android.software.app_widgets", false),
+            new Feature("android.software.input_methods", false),
+            new Feature("android.software.home_screen", false),
+            new Feature("android.hardware.bluetooth_le", false),
+            new Feature("android.hardware.camera.any", false),
+    };
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -202,6 +210,9 @@
 
         // add features from latest to last so that the latest requirements are put in the set first
         int apiVersion = Build.VERSION.SDK_INT;
+        if (apiVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+            Collections.addAll(features, ALL_JELLY_BEAN_MR2_FEATURES);
+        }
         if (apiVersion >= Build.VERSION_CODES.JELLY_BEAN) {
             Collections.addAll(features, ALL_JELLY_BEAN_FEATURES);
         }
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
index 79b2e57..70d6f58 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
@@ -21,6 +21,7 @@
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
+import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
@@ -30,6 +31,8 @@
 import android.test.AndroidTestCase;
 
 import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
 
 public class MediaStore_FilesTest extends AndroidTestCase {
@@ -150,6 +153,133 @@
         }
     }
 
+    public void testAccess() throws IOException {
+        // clean up from previous run
+        mResolver.delete(MediaStore.Images.Media.INTERNAL_CONTENT_URI,
+                "_data NOT LIKE ?", new String[] { "/system/%" } );
+
+        // insert some dummy starter data into the provider
+        ContentValues values = new ContentValues();
+        values.put(MediaStore.Images.Media.DISPLAY_NAME, "My Bitmap");
+        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
+        values.put(MediaStore.Images.Media.DATA, "/mnt/sdcard/dummy.jpg");
+        Uri uri = mResolver.insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
+
+        // point _data at directory and try to get an fd for it
+        values = new ContentValues();
+        values.put("_data", "/data/media");
+        mResolver.update(uri, values, null, null);
+        ParcelFileDescriptor pfd = null;
+        try {
+            pfd = mResolver.openFileDescriptor(uri, "r");
+            pfd.close();
+            fail("shouldn't be here");
+        } catch (FileNotFoundException e) {
+            // expected
+        }
+
+        // try to create a file in a place we don't have access to
+        values = new ContentValues();
+        values.put("_data", "/data/media/test.dat");
+        mResolver.update(uri, values, null, null);
+        try {
+            pfd = mResolver.openFileDescriptor(uri, "w");
+            pfd.close();
+            fail("shouldn't be here");
+        } catch (FileNotFoundException e) {
+            // expected
+        }
+        // read file back
+        try {
+            pfd = mResolver.openFileDescriptor(uri, "r");
+            pfd.close();
+            fail("shouldn't be here");
+        } catch (FileNotFoundException e) {
+            // expected
+        }
+
+        // point _data at media database and read it
+        values = new ContentValues();
+        values.put("_data", "/data/data/com.android.providers.media/databases/internal.db");
+        mResolver.update(uri, values, null, null);
+        try {
+            pfd = mResolver.openFileDescriptor(uri, "r");
+            pfd.close();
+            fail("shouldn't be here");
+        } catch (FileNotFoundException e) {
+            // expected
+        }
+
+        // Insert a private file into the database. Since it's private, the media provider won't
+        // be able to open it
+        FileOutputStream fos = mContext.openFileOutput("dummy.dat", Context.MODE_PRIVATE);
+        fos.write(0);
+        fos.close();
+        File path = mContext.getFileStreamPath("dummy.dat");
+        values = new ContentValues();
+        values.put("_data", path.getAbsolutePath());
+
+        mResolver.update(uri, values, null, null);
+        try {
+            pfd = mResolver.openFileDescriptor(uri, "r");
+            pfd.close();
+            fail("shouldn't be here");
+        } catch (FileNotFoundException e) {
+            // expected
+        }
+        // now make the file world-readable
+        fos = mContext.openFileOutput("dummy.dat", Context.MODE_WORLD_READABLE);
+        fos.write(0);
+        fos.close();
+        try {
+            pfd = mResolver.openFileDescriptor(uri, "r");
+            pfd.close();
+        } catch (FileNotFoundException e) {
+            fail("failed to open file");
+        }
+        path.delete();
+
+        File sdfile = null;
+        if (Environment.isExternalStorageEmulated()) {
+            // create file on sdcard and check access via real path
+            String fileDir = Environment.getExternalStorageDirectory() +
+                    "/" + getClass().getCanonicalName() + "/test.mp3";
+            sdfile = new File(fileDir);
+            writeFile(R.raw.testmp3, sdfile.getCanonicalPath());
+            assertTrue(sdfile.exists());
+            values = new ContentValues();
+            values.put("_data", sdfile.getCanonicalPath());
+            mResolver.update(uri, values, null, null);
+            try {
+                pfd = mResolver.openFileDescriptor(uri, "r");
+
+                // get the real path from the file descriptor
+                File real = new File("/proc/self/fd/" + pfd.getFd());
+                values = new ContentValues();
+                values.put("_data", real.getCanonicalPath());
+                mResolver.update(uri, values, null, null);
+                pfd.close();
+
+                // we shouldn't be able to access this
+                try {
+                    pfd = mResolver.openFileDescriptor(uri, "r");
+                    pfd.close();
+                    fail("shouldn't be here");
+                } catch (FileNotFoundException e) {
+                    // expected
+                }
+            } catch (FileNotFoundException e) {
+                fail("couldn't open file");
+            }
+        }
+
+        // clean up
+        assertEquals(1, mResolver.delete(uri, null, null));
+        if (sdfile != null) {
+            sdfile.delete();
+        }
+    }
+
     private void writeFile(int resid, String path) throws IOException {
         File out = new File(path);
         File dir = out.getParentFile();
diff --git a/tests/tests/provider/src/android/provider/cts/VoicemailContractTest.java b/tests/tests/provider/src/android/provider/cts/VoicemailContractTest.java
index ffb60f4..34a546e 100644
--- a/tests/tests/provider/src/android/provider/cts/VoicemailContractTest.java
+++ b/tests/tests/provider/src/android/provider/cts/VoicemailContractTest.java
@@ -21,6 +21,7 @@
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.RemoteException;
 import android.provider.VoicemailContract;
 import android.provider.VoicemailContract.Status;
 import android.provider.VoicemailContract.Voicemails;
@@ -140,6 +141,66 @@
         cursor.close();
     }
 
+    // Data column should be automatically generated during insert.
+    public void testInsert_doesNotUpdateDataColumn() throws Exception {
+
+        final String newFilePath = "my/new/file/path";
+        final ContentValues value = buildContentValuesForNewVoicemail();
+        value.put(Voicemails._DATA, newFilePath);
+        mVoicemailProvider.insert(mVoicemailContentUri, value);
+
+        assertDataNotEquals(newFilePath);
+    }
+
+    public void testDataColumnUpdate_throwsIllegalArgumentException() throws Exception {
+
+        final ContentValues value = buildContentValuesForNewVoicemail();
+        final Uri uri = mVoicemailProvider.insert(mVoicemailContentUri, value);
+
+        // Test: update
+        final String newFilePath = "another/file/path";
+
+        value.clear();
+        value.put(Voicemails._DATA, newFilePath);
+        try {
+            mVoicemailProvider.update(uri, value, null, null);
+            fail("IllegalArgumentException expected but not thrown.");
+        } catch (IllegalArgumentException e) {
+            // pass
+        }
+
+        assertDataNotEquals(newFilePath);
+    }
+
+    private void assertDataNotEquals(String newFilePath) throws RemoteException {
+        // Make sure data value is not actually updated.
+        final Cursor cursor = mVoicemailProvider.query(mVoicemailContentUri,
+                new String[]{Voicemails._DATA}, null, null, null);
+        cursor.moveToNext();
+        final String data = cursor.getString(0);
+        assertFalse(data.equals(newFilePath));
+    }
+
+    private ContentValues buildContentValuesForNewVoicemail() {
+        final String insertCallsNumber = "0123456789";
+        final long insertCallsDuration = 120;
+        final String insertSourceData = "internal_id";
+        final String insertMimeType = "audio/mp3";
+        final long insertDate = 1324478862000L;
+
+        ContentValues value = new ContentValues();
+        value.put(Voicemails.NUMBER, insertCallsNumber);
+        value.put(Voicemails.DATE, insertDate);
+        value.put(Voicemails.DURATION, insertCallsDuration);
+        // Source package is expected to be inserted by the provider, if not set.
+        value.put(Voicemails.SOURCE_DATA, insertSourceData);
+        value.put(Voicemails.MIME_TYPE, insertMimeType);
+        value.put(Voicemails.IS_READ, false);
+        value.put(Voicemails.HAS_CONTENT, true);
+
+        return value;
+    }
+
     public void testStatusTable() throws Exception {
         final String[] STATUS_PROJECTION = new String[] {
                 Status._ID, Status.SOURCE_PACKAGE, Status.CONFIGURATION_STATE,