1c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh/* 2c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh * Copyright (C) 2010 The Android Open Source Project 3c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh * 4c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License"); 5c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh * you may not use this file except in compliance with the License. 6c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh * You may obtain a copy of the License at 7c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh * 8c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh * http://www.apache.org/licenses/LICENSE-2.0 9c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh * 10c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh * Unless required by applicable law or agreed to in writing, software 11c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS, 12c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh * See the License for the specific language governing permissions and 14c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh * limitations under the License. 15c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh */ 16c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh 17c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yehpackage com.android.camera; 18c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh 19d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yehimport android.content.ContentResolver; 20d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yehimport android.content.ContentValues; 21d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yehimport android.location.Location; 22d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yehimport android.net.Uri; 23c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yehimport android.os.Environment; 24c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yehimport android.os.StatFs; 25d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yehimport android.provider.MediaStore.Images; 26d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yehimport android.provider.MediaStore.Images.ImageColumns; 27c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yehimport android.util.Log; 28c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh 29721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yehimport java.io.File; 30d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yehimport java.io.FileOutputStream; 31721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh 32bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenpublic class Storage { 33c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh private static final String TAG = "CameraStorage"; 34c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh 358ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li public static final String DCIM = 36721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString(); 37721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh 38721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh public static final String DIRECTORY = DCIM + "/Camera"; 39721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh 40d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh // Match the code in MediaProvider.computeBucketValues(). 41d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh public static final String BUCKET_ID = 42d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh String.valueOf(DIRECTORY.toLowerCase().hashCode()); 43d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh 44c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh public static final long UNAVAILABLE = -1L; 45c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh public static final long PREPARING = -2L; 46c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh public static final long UNKNOWN_SIZE = -3L; 47a5edbe951a507a066f7601204e633dbd2dff3224Chih-yu Huang public static final long LOW_STORAGE_THRESHOLD= 50000000; 48a5edbe951a507a066f7601204e633dbd2dff3224Chih-yu Huang public static final long PICTURE_SIZE = 1500000; 49c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh 508ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li private static final int BUFSIZE = 4096; 51d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh 52ea312297ff6132bbafed99b90a72e4858b888fa4Angus Kong public static Uri addImage(ContentResolver resolver, String title, long date, 53ea312297ff6132bbafed99b90a72e4858b888fa4Angus Kong Location location, int orientation, byte[] jpeg, int width, int height) { 54d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh // Save the image. 55e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen String path = generateFilepath(title); 56d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh FileOutputStream out = null; 57d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh try { 58d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh out = new FileOutputStream(path); 59d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh out.write(jpeg); 60d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh } catch (Exception e) { 61d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh Log.e(TAG, "Failed to write image", e); 62d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh return null; 63d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh } finally { 64d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh try { 65d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh out.close(); 66d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh } catch (Exception e) { 67d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh } 68d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh } 69d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh 700aaed976b603c56006213d196e6b0703285dafd5Chia-chi Yeh // Insert into MediaStore. 71d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh ContentValues values = new ContentValues(9); 72d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh values.put(ImageColumns.TITLE, title); 73d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh values.put(ImageColumns.DISPLAY_NAME, title + ".jpg"); 74d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh values.put(ImageColumns.DATE_TAKEN, date); 75d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh values.put(ImageColumns.MIME_TYPE, "image/jpeg"); 76d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh values.put(ImageColumns.ORIENTATION, orientation); 77d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh values.put(ImageColumns.DATA, path); 78d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh values.put(ImageColumns.SIZE, jpeg.length); 79ea312297ff6132bbafed99b90a72e4858b888fa4Angus Kong values.put(ImageColumns.WIDTH, width); 80ea312297ff6132bbafed99b90a72e4858b888fa4Angus Kong values.put(ImageColumns.HEIGHT, height); 81d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh 82d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh if (location != null) { 83d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh values.put(ImageColumns.LATITUDE, location.getLatitude()); 84d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh values.put(ImageColumns.LONGITUDE, location.getLongitude()); 85d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh } 86d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh 8780efb2ecfb09db1ac0915b13a91165d06bfbee74Chih-Chung Chang Uri uri = null; 8880efb2ecfb09db1ac0915b13a91165d06bfbee74Chih-Chung Chang try { 8980efb2ecfb09db1ac0915b13a91165d06bfbee74Chih-Chung Chang uri = resolver.insert(Images.Media.EXTERNAL_CONTENT_URI, values); 9080efb2ecfb09db1ac0915b13a91165d06bfbee74Chih-Chung Chang } catch (Throwable th) { 9180efb2ecfb09db1ac0915b13a91165d06bfbee74Chih-Chung Chang // This can happen when the external volume is already mounted, but 9280efb2ecfb09db1ac0915b13a91165d06bfbee74Chih-Chung Chang // MediaScanner has not notify MediaProvider to add that volume. 9380efb2ecfb09db1ac0915b13a91165d06bfbee74Chih-Chung Chang // The picture is still safe and MediaScanner will find it and 9480efb2ecfb09db1ac0915b13a91165d06bfbee74Chih-Chung Chang // insert it into MediaProvider. The only problem is that the user 9580efb2ecfb09db1ac0915b13a91165d06bfbee74Chih-Chung Chang // cannot click the thumbnail to review the picture. 9680efb2ecfb09db1ac0915b13a91165d06bfbee74Chih-Chung Chang Log.e(TAG, "Failed to write MediaStore" + th); 970aaed976b603c56006213d196e6b0703285dafd5Chia-chi Yeh } 988ab2b624d51b3b8254ece98c46a7e22a6fb5d4aaWu-cheng Li return uri; 99d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh } 100d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh 101e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen public static String generateFilepath(String title) { 102e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen return DIRECTORY + '/' + title + ".jpg"; 103e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen } 104e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen 105c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh public static long getAvailableSpace() { 106721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh String state = Environment.getExternalStorageState(); 107595d33f1308089ea4e656e247548a71b218d9fa5Wu-cheng Li Log.d(TAG, "External storage state=" + state); 108721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh if (Environment.MEDIA_CHECKING.equals(state)) { 109721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh return PREPARING; 110721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh } 111721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh if (!Environment.MEDIA_MOUNTED.equals(state)) { 112721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh return UNAVAILABLE; 113721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh } 114721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh 115721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh File dir = new File(DIRECTORY); 116721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh dir.mkdirs(); 117721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh if (!dir.isDirectory() || !dir.canWrite()) { 118721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh return UNAVAILABLE; 119721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh } 120721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh 121c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh try { 122721d2d2a963799fad4bda9bb4b278c24fc469303Chia-chi Yeh StatFs stat = new StatFs(DIRECTORY); 123c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh return stat.getAvailableBlocks() * (long) stat.getBlockSize(); 124c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh } catch (Exception e) { 125c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh Log.i(TAG, "Fail to access external storage", e); 126c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh } 127c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh return UNKNOWN_SIZE; 128c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh } 129d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh 130d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh /** 131d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh * OSX requires plugged-in USB storage to have path /DCIM/NNNAAAAA to be 132d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh * imported. This is a temporary fix for bug#1655552. 133d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh */ 134d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh public static void ensureOSXCompatible() { 13507713606e48802a2516c34c9bb9df4fc7f77553fWu-cheng Li File nnnAAAAA = new File(DCIM, "100ANDRO"); 136d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh if (!(nnnAAAAA.exists() || nnnAAAAA.mkdirs())) { 137d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh Log.e(TAG, "Failed to create " + nnnAAAAA.getPath()); 138d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh } 139d1ec4e36667086836cd243bee38aded5e1fd88b1Chia-chi Yeh } 140c8a7fc07e3b905a723e753b0c9144de2b0343f1fChia-chi Yeh} 141