Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.provider.cts;
     18 
     19 import android.provider.cts.R;
     20 
     21 import android.content.ContentResolver;
     22 import android.content.ContentUris;
     23 import android.content.ContentValues;
     24 import android.content.Context;
     25 import android.database.Cursor;
     26 import android.graphics.Bitmap;
     27 import android.graphics.BitmapFactory;
     28 import android.net.Uri;
     29 import android.os.Environment;
     30 import android.provider.MediaStore;
     31 import android.provider.MediaStore.Images.Media;
     32 import android.provider.MediaStore.Images.Thumbnails;
     33 import android.provider.MediaStore.MediaColumns;
     34 import android.test.InstrumentationTestCase;
     35 
     36 import com.android.compatibility.common.util.FileCopyHelper;
     37 
     38 import java.io.File;
     39 import java.util.ArrayList;
     40 import android.util.DisplayMetrics;
     41 
     42 public class MediaStore_Images_ThumbnailsTest extends InstrumentationTestCase {
     43     private ArrayList<Uri> mRowsAdded;
     44 
     45     private Context mContext;
     46 
     47     private ContentResolver mContentResolver;
     48 
     49     private FileCopyHelper mHelper;
     50 
     51     @Override
     52     protected void tearDown() throws Exception {
     53         for (Uri row : mRowsAdded) {
     54             try {
     55                 mContentResolver.delete(row, null, null);
     56             } catch (UnsupportedOperationException e) {
     57                 // There is no way to delete rows from table "thumbnails" of internals database.
     58                 // ignores the exception and make the loop goes on
     59             }
     60         }
     61 
     62         mHelper.clear();
     63         super.tearDown();
     64     }
     65 
     66     @Override
     67     protected void setUp() throws Exception {
     68         super.setUp();
     69 
     70         mContext = getInstrumentation().getTargetContext();
     71         mContentResolver = mContext.getContentResolver();
     72 
     73         mHelper = new FileCopyHelper(mContext);
     74         mRowsAdded = new ArrayList<Uri>();
     75     }
     76 
     77     public void testQueryInternalThumbnails() throws Exception {
     78         Cursor c = Thumbnails.queryMiniThumbnails(mContentResolver,
     79                 Thumbnails.INTERNAL_CONTENT_URI, Thumbnails.MICRO_KIND, null);
     80         int previousMicroKindCount = c.getCount();
     81         c.close();
     82 
     83         // add a thumbnail
     84         String path = mHelper.copy(R.raw.scenery, "testThumbnails.jpg");
     85         ContentValues values = new ContentValues();
     86         values.put(Thumbnails.KIND, Thumbnails.MINI_KIND);
     87         values.put(Thumbnails.DATA, path);
     88         Uri uri = mContentResolver.insert(Thumbnails.INTERNAL_CONTENT_URI, values);
     89         if (uri != null) {
     90             mRowsAdded.add(uri);
     91         }
     92 
     93         // query with the uri of the thumbnail and the kind
     94         c = Thumbnails.queryMiniThumbnails(mContentResolver, uri, Thumbnails.MINI_KIND, null);
     95         c.moveToFirst();
     96         assertEquals(1, c.getCount());
     97         assertEquals(Thumbnails.MINI_KIND, c.getInt(c.getColumnIndex(Thumbnails.KIND)));
     98         assertEquals(path, c.getString(c.getColumnIndex(Thumbnails.DATA)));
     99 
    100         // query all thumbnails with other kind
    101         c = Thumbnails.queryMiniThumbnails(mContentResolver, Thumbnails.INTERNAL_CONTENT_URI,
    102                 Thumbnails.MICRO_KIND, null);
    103         assertEquals(previousMicroKindCount, c.getCount());
    104         c.close();
    105 
    106         // query without kind
    107         c = Thumbnails.query(mContentResolver, uri, null);
    108         assertEquals(1, c.getCount());
    109         c.moveToFirst();
    110         assertEquals(Thumbnails.MINI_KIND, c.getInt(c.getColumnIndex(Thumbnails.KIND)));
    111         assertEquals(path, c.getString(c.getColumnIndex(Thumbnails.DATA)));
    112         c.close();
    113     }
    114 
    115     public void testQueryExternalMiniThumbnails() {
    116         // insert the image by bitmap
    117         BitmapFactory.Options opts = new BitmapFactory.Options();
    118         opts.inTargetDensity = DisplayMetrics.DENSITY_XHIGH;
    119         Bitmap src = BitmapFactory.decodeResource(mContext.getResources(), R.raw.scenery,opts);
    120         String stringUrl = null;
    121         try{
    122             stringUrl = Media.insertImage(mContentResolver, src, null, null);
    123         } catch (UnsupportedOperationException e) {
    124             // the tests will be aborted because the image will be put in sdcard
    125             fail("There is no sdcard attached! " + e.getMessage());
    126         }
    127         assertNotNull(stringUrl);
    128         Uri stringUri = Uri.parse(stringUrl);
    129         mRowsAdded.add(stringUri);
    130 
    131         // get the original image id and path
    132         Cursor c = mContentResolver.query(stringUri,
    133                 new String[]{ Media._ID, Media.DATA }, null, null, null);
    134         c.moveToFirst();
    135         long imageId = c.getLong(c.getColumnIndex(Media._ID));
    136         String imagePath = c.getString(c.getColumnIndex(Media.DATA));
    137         c.close();
    138 
    139         assertTrue("image file does not exist", new File(imagePath).exists());
    140 
    141         String[] sizeProjection = new String[] { Thumbnails.WIDTH, Thumbnails.HEIGHT };
    142         c = Thumbnails.queryMiniThumbnail(mContentResolver, imageId, Thumbnails.MINI_KIND,
    143                 sizeProjection);
    144         assertEquals(1, c.getCount());
    145         assertTrue(c.moveToFirst());
    146         assertTrue(c.getLong(c.getColumnIndex(Thumbnails.WIDTH)) >= Math.min(src.getWidth(), 240));
    147         assertTrue(c.getLong(c.getColumnIndex(Thumbnails.HEIGHT)) >= Math.min(src.getHeight(), 240));
    148         c.close();
    149         c = Thumbnails.queryMiniThumbnail(mContentResolver, imageId, Thumbnails.MICRO_KIND,
    150                 sizeProjection);
    151         assertEquals(1, c.getCount());
    152         assertTrue(c.moveToFirst());
    153         assertEquals(50, c.getLong(c.getColumnIndex(Thumbnails.WIDTH)));
    154         assertEquals(50, c.getLong(c.getColumnIndex(Thumbnails.HEIGHT)));
    155         c.close();
    156 
    157         c = Thumbnails.queryMiniThumbnail(mContentResolver, imageId, Thumbnails.MINI_KIND,
    158                 new String[] { Thumbnails._ID, Thumbnails.DATA, Thumbnails.IMAGE_ID});
    159 
    160         c.moveToNext();
    161         long img = c.getLong(c.getColumnIndex(Thumbnails.IMAGE_ID));
    162         assertEquals(imageId, img);
    163         String thumbPath = c.getString(c.getColumnIndex(Thumbnails.DATA));
    164         assertTrue("thumbnail file does not exist", new File(thumbPath).exists());
    165 
    166         // deleting the image from the database also deletes the image file, and the
    167         // corresponding entry in the thumbnail table, which in turn triggers deletion
    168         // of the thumbnail file on disk
    169         mContentResolver.delete(stringUri, null, null);
    170         mRowsAdded.remove(stringUri);
    171 
    172         assertFalse("image file should no longer exist", new File(imagePath).exists());
    173 
    174         Cursor c2 = Thumbnails.queryMiniThumbnail(mContentResolver, imageId, Thumbnails.MINI_KIND,
    175                 new String[] { Thumbnails._ID, Thumbnails.DATA, Thumbnails.IMAGE_ID});
    176         assertEquals(0, c2.getCount());
    177         c2.close();
    178 
    179         assertFalse("thumbnail file should no longer exist", new File(thumbPath).exists());
    180         c.close();
    181 
    182         // insert image, then delete it via the files table
    183         stringUrl = Media.insertImage(mContentResolver, src, null, null);
    184         c = mContentResolver.query(Uri.parse(stringUrl),
    185                 new String[]{ Media._ID, Media.DATA}, null, null, null);
    186         c.moveToFirst();
    187         imageId = c.getLong(c.getColumnIndex(Media._ID));
    188         imagePath = c.getString(c.getColumnIndex(Media.DATA));
    189         c.close();
    190         assertTrue("image file does not exist", new File(imagePath).exists());
    191         Uri fileuri = MediaStore.Files.getContentUri("external", imageId);
    192         mContentResolver.delete(fileuri, null, null);
    193         assertFalse("image file should no longer exist", new File(imagePath).exists());
    194 
    195 
    196         // insert image, then delete its thumbnail
    197         stringUrl = Media.insertImage(mContentResolver, src, null, null);
    198         c = mContentResolver.query(Uri.parse(stringUrl),
    199                 new String[]{ Media._ID, Media.DATA}, null, null, null);
    200         c.moveToFirst();
    201         imageId = c.getLong(c.getColumnIndex(Media._ID));
    202         imagePath = c.getString(c.getColumnIndex(Media.DATA));
    203         c.close();
    204         c2 = Thumbnails.queryMiniThumbnail(mContentResolver, imageId, Thumbnails.MINI_KIND,
    205                 new String[] { Thumbnails._ID, Thumbnails.DATA, Thumbnails.IMAGE_ID});
    206         c2.moveToFirst();
    207         thumbPath = c2.getString(c2.getColumnIndex(Thumbnails.DATA));
    208         assertTrue("thumbnail file does not exist", new File(thumbPath).exists());
    209 
    210         Uri imguri = Uri.parse(stringUrl);
    211         long imgid = ContentUris.parseId(imguri);
    212         assertEquals(imgid, imageId);
    213         mRowsAdded.add(imguri);
    214         mContentResolver.delete(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
    215                 MediaStore.Images.Thumbnails.IMAGE_ID + "=?", new String[]{ "" + imgid});
    216         assertFalse("thumbnail file should no longer exist", new File(thumbPath).exists());
    217         assertTrue("image file should still exist", new File(imagePath).exists());
    218     }
    219 
    220     public void testGetContentUri() {
    221         Cursor c = null;
    222         assertNotNull(c = mContentResolver.query(Thumbnails.getContentUri("internal"), null, null,
    223                 null, null));
    224         c.close();
    225         assertNotNull(c = mContentResolver.query(Thumbnails.getContentUri("external"), null, null,
    226                 null, null));
    227         c.close();
    228 
    229         // can not accept any other volume names
    230         String volume = "fakeVolume";
    231         assertNull(mContentResolver.query(Thumbnails.getContentUri(volume), null, null, null,
    232                 null));
    233     }
    234 
    235     public void testStoreImagesMediaExternal() {
    236         final String externalImgPath = Environment.getExternalStorageDirectory() +
    237                 "/testimage.jpg";
    238         final String externalImgPath2 = Environment.getExternalStorageDirectory() +
    239                 "/testimage1.jpg";
    240         ContentValues values = new ContentValues();
    241         values.put(Thumbnails.KIND, Thumbnails.FULL_SCREEN_KIND);
    242         values.put(Thumbnails.IMAGE_ID, 0);
    243         values.put(Thumbnails.HEIGHT, 480);
    244         values.put(Thumbnails.WIDTH, 320);
    245         values.put(Thumbnails.DATA, externalImgPath);
    246 
    247         // insert
    248         Uri uri = mContentResolver.insert(Thumbnails.EXTERNAL_CONTENT_URI, values);
    249         assertNotNull(uri);
    250 
    251         // query
    252         Cursor c = mContentResolver.query(uri, null, null, null, null);
    253         assertEquals(1, c.getCount());
    254         c.moveToFirst();
    255         long id = c.getLong(c.getColumnIndex(Thumbnails._ID));
    256         assertTrue(id > 0);
    257         assertEquals(Thumbnails.FULL_SCREEN_KIND, c.getInt(c.getColumnIndex(Thumbnails.KIND)));
    258         assertEquals(0, c.getLong(c.getColumnIndex(Thumbnails.IMAGE_ID)));
    259         assertEquals(480, c.getInt(c.getColumnIndex(Thumbnails.HEIGHT)));
    260         assertEquals(320, c.getInt(c.getColumnIndex(Thumbnails.WIDTH)));
    261         assertEquals(externalImgPath, c.getString(c.getColumnIndex(Thumbnails.DATA)));
    262         c.close();
    263 
    264         // update
    265         values.clear();
    266         values.put(Thumbnails.KIND, Thumbnails.MICRO_KIND);
    267         values.put(Thumbnails.IMAGE_ID, 1);
    268         values.put(Thumbnails.HEIGHT, 50);
    269         values.put(Thumbnails.WIDTH, 50);
    270         values.put(Thumbnails.DATA, externalImgPath2);
    271         assertEquals(1, mContentResolver.update(uri, values, null, null));
    272 
    273         // delete
    274         assertEquals(1, mContentResolver.delete(uri, null, null));
    275     }
    276 
    277     public void testThumbnailGenerationAndCleanup() throws Exception {
    278         // insert an image
    279         Bitmap src = BitmapFactory.decodeResource(mContext.getResources(), R.raw.scenery);
    280         Uri uri = Uri.parse(Media.insertImage(mContentResolver, src, "test", "test description"));
    281 
    282         // query its thumbnail
    283         Cursor c = mContentResolver.query(
    284                 Thumbnails.EXTERNAL_CONTENT_URI,
    285                 new String [] {Thumbnails.DATA},
    286                 "image_id=?",
    287                 new String[] {uri.getLastPathSegment()},
    288                 null /* sort */
    289                 );
    290         assertTrue("couldn't find thumbnail", c.moveToNext());
    291         String path = c.getString(0);
    292         c.close();
    293         assertTrue("thumbnail does not exist", new File(path).exists());
    294 
    295         // delete the source image and check that the thumbnail is gone too
    296         mContentResolver.delete(uri, null /* where clause */, null /* where args */);
    297         assertFalse("thumbnail still exists after source file delete", new File(path).exists());
    298 
    299         // insert again
    300         uri = Uri.parse(Media.insertImage(mContentResolver, src, "test", "test description"));
    301 
    302         // query its thumbnail again
    303         c = mContentResolver.query(
    304                 Thumbnails.EXTERNAL_CONTENT_URI,
    305                 new String [] {Thumbnails.DATA},
    306                 "image_id=?",
    307                 new String[] {uri.getLastPathSegment()},
    308                 null /* sortOrder */
    309                 );
    310         assertTrue("couldn't find thumbnail", c.moveToNext());
    311         path = c.getString(0);
    312         c.close();
    313         assertTrue("thumbnail does not exist", new File(path).exists());
    314 
    315         // update the media type
    316         ContentValues values = new ContentValues();
    317         values.put("media_type", 0);
    318         assertEquals("unexpected number of updated rows",
    319                 1, mContentResolver.update(uri, values, null /* where */, null /* where args */));
    320 
    321         // image was marked as regular file in the database, which should have deleted its thumbnail
    322 
    323         // query its thumbnail again
    324         c = mContentResolver.query(
    325                 Thumbnails.EXTERNAL_CONTENT_URI,
    326                 new String [] {Thumbnails.DATA},
    327                 "image_id=?",
    328                 new String[] {uri.getLastPathSegment()},
    329                 null /* sort */
    330                 );
    331         if (c != null) {
    332             assertFalse("thumbnail entry exists for non-thumbnail file", c.moveToNext());
    333             c.close();
    334         }
    335         assertFalse("thumbnail remains after source file type change", new File(path).exists());
    336 
    337         // check source no longer exists as image
    338         c = mContentResolver.query(uri,
    339                 null /* projection */, null /* where */, null /* where args */, null /* sort */);
    340         assertFalse("source entry should be gone", c.moveToNext());
    341         c.close();
    342 
    343         // check source still exists as file
    344         Uri fileUri = ContentUris.withAppendedId(
    345                 MediaStore.Files.getContentUri("external"),
    346                 Long.valueOf(uri.getLastPathSegment()));
    347         c = mContentResolver.query(fileUri,
    348                 null /* projection */, null /* where */, null /* where args */, null /* sort */);
    349         assertTrue("source entry is gone", c.moveToNext());
    350         String sourcePath = c.getString(c.getColumnIndex("_data"));
    351         c.close();
    352 
    353         // clean up
    354         mContentResolver.delete(uri, null /* where */, null /* where args */);
    355         new File(sourcePath).delete();
    356     }
    357 
    358     public void testStoreImagesMediaInternal() {
    359         // can not insert any data, so other operations can not be tested
    360         try {
    361             mContentResolver.insert(Thumbnails.INTERNAL_CONTENT_URI, new ContentValues());
    362             fail("Should throw UnsupportedOperationException when inserting into internal "
    363                     + "database");
    364         } catch (UnsupportedOperationException e) {
    365             // expected
    366         }
    367     }
    368 
    369     public void testThumbnailOrderedQuery() throws Exception {
    370         Bitmap src = BitmapFactory.decodeResource(mContext.getResources(), R.raw.scenery);
    371         Uri url[] = new Uri[3];
    372         try{
    373             for (int i = 0; i < url.length; i++) {
    374                 url[i] = Uri.parse(Media.insertImage(mContentResolver, src, null, null));
    375                 long origId = Long.parseLong(url[i].getLastPathSegment());
    376                 Bitmap foo = MediaStore.Images.Thumbnails.getThumbnail(mContentResolver,
    377                         origId, Thumbnails.MICRO_KIND, null);
    378                 assertNotNull(foo);
    379             }
    380 
    381             // remove one of the images, its thumbnail, and the thumbnail cache
    382             Cursor c = mContentResolver.query(url[1], null, null, null, null);
    383             assertEquals(1, c.getCount());
    384             c.moveToFirst();
    385             String path = c.getString(c.getColumnIndex(MediaColumns.DATA));
    386             long id = c.getLong(c.getColumnIndex(MediaColumns._ID));
    387             c.close();
    388             assertTrue(new File(path).delete());
    389 
    390             long removedId = Long.parseLong(url[1].getLastPathSegment());
    391             long remainingId1 = Long.parseLong(url[0].getLastPathSegment());
    392             long remainingId2 = Long.parseLong(url[2].getLastPathSegment());
    393             c = mContentResolver.query(
    394                     MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, null,
    395                     Thumbnails.IMAGE_ID + "=?", new String[] { Long.toString(removedId) }, null);
    396             assertTrue(c.getCount() > 0);  // one or more thumbnail kinds
    397             while (c.moveToNext()) {
    398                 path = c.getString(c.getColumnIndex(MediaColumns.DATA));
    399                 assertTrue(new File(path).delete());
    400             }
    401             c.close();
    402 
    403             File thumbdir = new File(path).getParentFile();
    404             File[] list = thumbdir.listFiles();
    405             for (int i = 0; i < list.length; i++) {
    406                 if (list[i].getName().startsWith(".thumbdata")) {
    407                     assertTrue(list[i].delete());
    408                 }
    409             }
    410 
    411             // check if a thumbnail is still being returned for the image that was removed
    412             Bitmap foo = MediaStore.Images.Thumbnails.getThumbnail(mContentResolver,
    413                     removedId, Thumbnails.MICRO_KIND, null);
    414             assertNull(foo);
    415 
    416             for (String order: new String[] { " ASC", " DESC" }) {
    417                 c = mContentResolver.query(
    418                         MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null,
    419                         MediaColumns._ID + order);
    420                 while (c.moveToNext()) {
    421                     id = c.getLong(c.getColumnIndex(MediaColumns._ID));
    422                     foo = MediaStore.Images.Thumbnails.getThumbnail(
    423                             mContentResolver, id,
    424                             MediaStore.Images.Thumbnails.MICRO_KIND, null);
    425                     if (id == removedId) {
    426                         assertNull("unexpected bitmap with" + order + " ordering", foo);
    427                     } else if (id == remainingId1 || id == remainingId2) {
    428                         assertNotNull("missing bitmap with" + order + " ordering", foo);
    429                     }
    430                 }
    431                 c.close();
    432             }
    433         } catch (UnsupportedOperationException e) {
    434             // the tests will be aborted because the image will be put in sdcard
    435             fail("There is no sdcard attached! " + e.getMessage());
    436         }
    437     }
    438 }
    439