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