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 com.android.cts.provider.R; 20 21 import android.content.ContentResolver; 22 import android.content.ContentValues; 23 import android.content.Context; 24 import android.cts.util.FileCopyHelper; 25 import android.cts.util.FileUtils; 26 import android.database.Cursor; 27 import android.graphics.Bitmap; 28 import android.graphics.BitmapFactory; 29 import android.net.Uri; 30 import android.os.Environment; 31 import android.provider.MediaStore.Images.Media; 32 import android.provider.MediaStore.Images.Thumbnails; 33 import android.test.InstrumentationTestCase; 34 35 import java.io.File; 36 import java.io.FileNotFoundException; 37 import java.lang.Math; 38 import java.util.ArrayList; 39 40 public class MediaStore_Images_MediaTest extends InstrumentationTestCase { 41 private static final String MIME_TYPE_JPEG = "image/jpeg"; 42 43 private static final String TEST_TITLE1 = "test title1"; 44 45 private static final String TEST_DESCRIPTION1 = "test description1"; 46 47 private static final String TEST_TITLE2 = "test title2"; 48 49 private static final String TEST_DESCRIPTION2 = "test description2"; 50 51 private static final String TEST_TITLE3 = "test title3"; 52 53 private static final String TEST_DESCRIPTION3 = "test description3"; 54 55 private ArrayList<Uri> mRowsAdded; 56 57 private Context mContext; 58 59 private ContentResolver mContentResolver; 60 61 private FileCopyHelper mHelper; 62 63 @Override 64 protected void tearDown() throws Exception { 65 for (Uri row : mRowsAdded) { 66 mContentResolver.delete(row, null, null); 67 } 68 69 mHelper.clear(); 70 super.tearDown(); 71 } 72 73 @Override 74 protected void setUp() throws Exception { 75 super.setUp(); 76 77 mContext = getInstrumentation().getTargetContext(); 78 mContentResolver = mContext.getContentResolver(); 79 80 mHelper = new FileCopyHelper(mContext); 81 mRowsAdded = new ArrayList<Uri>(); 82 } 83 84 public void testInsertImageWithImagePath() throws Exception { 85 Cursor c = Media.query(mContentResolver, Media.EXTERNAL_CONTENT_URI, null, null, 86 "_id ASC"); 87 int previousCount = c.getCount(); 88 c.close(); 89 90 // insert an image by path 91 String path = mHelper.copy(R.raw.scenery, "mediaStoreTest1.jpg"); 92 String stringUrl = null; 93 try { 94 stringUrl = Media.insertImage(mContentResolver, path, TEST_TITLE1, TEST_DESCRIPTION1); 95 } catch (FileNotFoundException e) { 96 fail(e.getMessage()); 97 } catch (UnsupportedOperationException e) { 98 // the tests will be aborted because the image will be put in sdcard 99 fail("There is no sdcard attached! " + e.getMessage()); 100 } 101 assertInsertionSuccess(stringUrl); 102 mRowsAdded.add(Uri.parse(stringUrl)); 103 104 // insert another image by path 105 path = mHelper.copy(R.raw.scenery, "mediaStoreTest2.jpg"); 106 stringUrl = null; 107 try { 108 stringUrl = Media.insertImage(mContentResolver, path, TEST_TITLE2, TEST_DESCRIPTION2); 109 } catch (FileNotFoundException e) { 110 fail(e.getMessage()); 111 } catch (UnsupportedOperationException e) { 112 // the tests will be aborted because the image will be put in sdcard 113 fail("There is no sdcard attached! " + e.getMessage()); 114 } 115 assertInsertionSuccess(stringUrl); 116 mRowsAdded.add(Uri.parse(stringUrl)); 117 118 // query the newly added image 119 c = Media.query(mContentResolver, Uri.parse(stringUrl), 120 new String[] { Media.TITLE, Media.DESCRIPTION, Media.MIME_TYPE }); 121 assertEquals(1, c.getCount()); 122 c.moveToFirst(); 123 assertEquals(TEST_TITLE2, c.getString(c.getColumnIndex(Media.TITLE))); 124 assertEquals(TEST_DESCRIPTION2, c.getString(c.getColumnIndex(Media.DESCRIPTION))); 125 assertEquals(MIME_TYPE_JPEG, c.getString(c.getColumnIndex(Media.MIME_TYPE))); 126 c.close(); 127 128 // query all the images in external db and order them by descending id 129 // (make the images added in test case in the first positions) 130 c = Media.query(mContentResolver, Media.EXTERNAL_CONTENT_URI, 131 new String[] { Media.TITLE, Media.DESCRIPTION, Media.MIME_TYPE }, null, 132 "_id DESC"); 133 assertEquals(previousCount + 2, c.getCount()); 134 c.moveToFirst(); 135 assertEquals(TEST_TITLE2, c.getString(c.getColumnIndex(Media.TITLE))); 136 assertEquals(TEST_DESCRIPTION2, c.getString(c.getColumnIndex(Media.DESCRIPTION))); 137 assertEquals(MIME_TYPE_JPEG, c.getString(c.getColumnIndex(Media.MIME_TYPE))); 138 c.moveToNext(); 139 assertEquals(TEST_TITLE1, c.getString(c.getColumnIndex(Media.TITLE))); 140 assertEquals(TEST_DESCRIPTION1, c.getString(c.getColumnIndex(Media.DESCRIPTION))); 141 assertEquals(MIME_TYPE_JPEG, c.getString(c.getColumnIndex(Media.MIME_TYPE))); 142 c.close(); 143 144 // query the second image added in the test 145 c = Media.query(mContentResolver, Uri.parse(stringUrl), 146 new String[] { Media.DESCRIPTION, Media.MIME_TYPE }, Media.TITLE + "=?", 147 new String[] { TEST_TITLE2 }, "_id ASC"); 148 assertEquals(1, c.getCount()); 149 c.moveToFirst(); 150 assertEquals(TEST_DESCRIPTION2, c.getString(c.getColumnIndex(Media.DESCRIPTION))); 151 assertEquals(MIME_TYPE_JPEG, c.getString(c.getColumnIndex(Media.MIME_TYPE))); 152 c.close(); 153 } 154 155 public void testInsertImageWithBitmap() throws Exception { 156 // insert the image by bitmap 157 Bitmap src = BitmapFactory.decodeResource(mContext.getResources(), R.raw.scenery); 158 String stringUrl = null; 159 try{ 160 stringUrl = Media.insertImage(mContentResolver, src, TEST_TITLE3, TEST_DESCRIPTION3); 161 } catch (UnsupportedOperationException e) { 162 // the tests will be aborted because the image will be put in sdcard 163 fail("There is no sdcard attached! " + e.getMessage()); 164 } 165 assertInsertionSuccess(stringUrl); 166 mRowsAdded.add(Uri.parse(stringUrl)); 167 168 Cursor c = Media.query(mContentResolver, Uri.parse(stringUrl), new String[] { Media.DATA }, 169 null, "_id ASC"); 170 c.moveToFirst(); 171 // get the bimap by the path 172 Bitmap result = Media.getBitmap(mContentResolver, 173 Uri.fromFile(new File(c.getString(c.getColumnIndex(Media.DATA))))); 174 175 // can not check the identity between the result and source bitmap because 176 // source bitmap is compressed before it is saved as result bitmap 177 assertEquals(src.getWidth(), result.getWidth()); 178 assertEquals(src.getHeight(), result.getHeight()); 179 } 180 181 public void testGetContentUri() { 182 Cursor c = null; 183 assertNotNull(c = mContentResolver.query(Media.getContentUri("internal"), null, null, null, 184 null)); 185 c.close(); 186 assertNotNull(c = mContentResolver.query(Media.getContentUri("external"), null, null, null, 187 null)); 188 c.close(); 189 190 // can not accept any other volume names 191 String volume = "fakeVolume"; 192 assertNull(mContentResolver.query(Media.getContentUri(volume), null, null, null, null)); 193 } 194 195 private void cleanExternalMediaFile(String path) { 196 mContentResolver.delete(Media.EXTERNAL_CONTENT_URI, "_data=?", new String[] { path }); 197 new File(path).delete(); 198 } 199 200 public void testStoreImagesMediaExternal() throws Exception { 201 final String externalPath = Environment.getExternalStorageDirectory().getPath() + 202 "/testimage.jpg"; 203 final String externalPath2 = Environment.getExternalStorageDirectory().getPath() + 204 "/testimage1.jpg"; 205 206 // clean up any potential left over entries from a previous aborted run 207 cleanExternalMediaFile(externalPath); 208 cleanExternalMediaFile(externalPath2); 209 210 int numBytes = 1337; 211 FileUtils.createFile(new File(externalPath), numBytes); 212 213 ContentValues values = new ContentValues(); 214 values.put(Media.ORIENTATION, 0); 215 values.put(Media.PICASA_ID, 0); 216 long dateTaken = System.currentTimeMillis(); 217 values.put(Media.DATE_TAKEN, dateTaken); 218 values.put(Media.DESCRIPTION, "This is a image"); 219 values.put(Media.LATITUDE, 40.689060d); 220 values.put(Media.LONGITUDE, -74.044636d); 221 values.put(Media.IS_PRIVATE, 1); 222 values.put(Media.MINI_THUMB_MAGIC, 0); 223 values.put(Media.DATA, externalPath); 224 values.put(Media.DISPLAY_NAME, "testimage"); 225 values.put(Media.MIME_TYPE, "image/jpeg"); 226 values.put(Media.SIZE, numBytes); 227 values.put(Media.TITLE, "testimage"); 228 long dateAdded = System.currentTimeMillis() / 1000; 229 values.put(Media.DATE_ADDED, dateAdded); 230 long dateModified = System.currentTimeMillis() / 1000; 231 values.put(Media.DATE_MODIFIED, dateModified); 232 233 // insert 234 Uri uri = mContentResolver.insert(Media.EXTERNAL_CONTENT_URI, values); 235 assertNotNull(uri); 236 237 try { 238 // query 239 Cursor c = mContentResolver.query(uri, null, null, null, null); 240 assertEquals(1, c.getCount()); 241 c.moveToFirst(); 242 long id = c.getLong(c.getColumnIndex(Media._ID)); 243 assertTrue(id > 0); 244 assertEquals(0, c.getInt(c.getColumnIndex(Media.ORIENTATION))); 245 assertEquals(0, c.getLong(c.getColumnIndex(Media.PICASA_ID))); 246 assertEquals(dateTaken, c.getLong(c.getColumnIndex(Media.DATE_TAKEN))); 247 assertEquals("This is a image", 248 c.getString(c.getColumnIndex(Media.DESCRIPTION))); 249 assertEquals(40.689060d, c.getDouble(c.getColumnIndex(Media.LATITUDE)), 0d); 250 assertEquals(-74.044636d, c.getDouble(c.getColumnIndex(Media.LONGITUDE)), 0d); 251 assertEquals(1, c.getInt(c.getColumnIndex(Media.IS_PRIVATE))); 252 assertEquals(0, c.getLong(c.getColumnIndex(Media.MINI_THUMB_MAGIC))); 253 assertEquals(externalPath, c.getString(c.getColumnIndex(Media.DATA))); 254 assertEquals("testimage", c.getString(c.getColumnIndex(Media.DISPLAY_NAME))); 255 assertEquals("image/jpeg", c.getString(c.getColumnIndex(Media.MIME_TYPE))); 256 assertEquals("testimage", c.getString(c.getColumnIndex(Media.TITLE))); 257 assertEquals(numBytes, c.getInt(c.getColumnIndex(Media.SIZE))); 258 long realDateAdded = c.getLong(c.getColumnIndex(Media.DATE_ADDED)); 259 assertTrue(realDateAdded >= dateAdded); 260 // there can be delay as time is read after creation 261 assertTrue(Math.abs(dateModified - c.getLong(c.getColumnIndex(Media.DATE_MODIFIED))) 262 < 5); 263 c.close(); 264 265 // update 266 values.clear(); 267 values.put(Media.ORIENTATION, 90); 268 values.put(Media.PICASA_ID, 10); 269 dateTaken = System.currentTimeMillis(); 270 values.put(Media.DATE_TAKEN, dateTaken); 271 values.put(Media.DESCRIPTION, "This is another image"); 272 values.put(Media.LATITUDE, 41.689060d); 273 values.put(Media.LONGITUDE, -75.044636d); 274 values.put(Media.IS_PRIVATE, 0); 275 values.put(Media.MINI_THUMB_MAGIC, 2); 276 values.put(Media.DATA, externalPath2); 277 values.put(Media.DISPLAY_NAME, "testimage1"); 278 values.put(Media.MIME_TYPE, "image/jpeg"); 279 values.put(Media.SIZE, 86854); 280 values.put(Media.TITLE, "testimage1"); 281 dateModified = System.currentTimeMillis() / 1000; 282 values.put(Media.DATE_MODIFIED, dateModified); 283 assertEquals(1, mContentResolver.update(uri, values, null, null)); 284 285 c = mContentResolver.query(uri, null, null, null, null); 286 assertEquals(1, c.getCount()); 287 c.moveToFirst(); 288 assertEquals(id, c.getLong(c.getColumnIndex(Media._ID))); 289 assertEquals(90, c.getInt(c.getColumnIndex(Media.ORIENTATION))); 290 assertEquals(10, c.getInt(c.getColumnIndex(Media.PICASA_ID))); 291 assertEquals(dateTaken, c.getLong(c.getColumnIndex(Media.DATE_TAKEN))); 292 assertEquals("This is another image", 293 c.getString(c.getColumnIndex(Media.DESCRIPTION))); 294 assertEquals(41.689060d, c.getDouble(c.getColumnIndex(Media.LATITUDE)), 0d); 295 assertEquals(-75.044636d, c.getDouble(c.getColumnIndex(Media.LONGITUDE)), 0d); 296 assertEquals(0, c.getInt(c.getColumnIndex(Media.IS_PRIVATE))); 297 assertEquals(2, c.getLong(c.getColumnIndex(Media.MINI_THUMB_MAGIC))); 298 assertEquals(externalPath2, 299 c.getString(c.getColumnIndex(Media.DATA))); 300 assertEquals("testimage1", c.getString(c.getColumnIndex(Media.DISPLAY_NAME))); 301 assertEquals("image/jpeg", c.getString(c.getColumnIndex(Media.MIME_TYPE))); 302 assertEquals("testimage1", c.getString(c.getColumnIndex(Media.TITLE))); 303 assertEquals(86854, c.getInt(c.getColumnIndex(Media.SIZE))); 304 assertEquals(realDateAdded, c.getLong(c.getColumnIndex(Media.DATE_ADDED))); 305 assertEquals(dateModified, c.getLong(c.getColumnIndex(Media.DATE_MODIFIED))); 306 c.close(); 307 } finally { 308 // delete 309 assertEquals(1, mContentResolver.delete(uri, null, null)); 310 new File(externalPath).delete(); 311 } 312 } 313 314 public void testStoreImagesMediaInternal() { 315 // can not insert any data, so other operations can not be tested 316 try { 317 mContentResolver.insert(Media.INTERNAL_CONTENT_URI, new ContentValues()); 318 fail("Should throw UnsupportedOperationException when inserting into internal " 319 + "database"); 320 } catch (UnsupportedOperationException e) { 321 } 322 } 323 324 private void assertInsertionSuccess(String stringUrl) { 325 assertNotNull(stringUrl); 326 // check whether the thumbnails are generated 327 Cursor c = mContentResolver.query(Uri.parse(stringUrl), new String[]{ Media._ID }, null, 328 null, null); 329 assertTrue(c.moveToFirst()); 330 long imageId = c.getLong(c.getColumnIndex(Media._ID)); 331 c.close(); 332 assertNotNull(Thumbnails.getThumbnail(mContentResolver, imageId, 333 Thumbnails.MINI_KIND, null)); 334 assertNotNull(Thumbnails.getThumbnail(mContentResolver, imageId, 335 Thumbnails.MICRO_KIND, null)); 336 c = mContentResolver.query(Thumbnails.EXTERNAL_CONTENT_URI, null, 337 Thumbnails.IMAGE_ID + "=" + imageId, null, null); 338 assertEquals(2, c.getCount()); 339 c.close(); 340 } 341 } 342