1/*
2 * Copyright (C) 2010 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
17package com.android.camera;
18
19import android.content.ContentResolver;
20import android.content.ContentValues;
21import android.location.Location;
22import android.net.Uri;
23import android.os.Environment;
24import android.os.StatFs;
25import android.provider.MediaStore.Images;
26import android.provider.MediaStore.Images.ImageColumns;
27import android.util.Log;
28
29import java.io.File;
30import java.io.FileOutputStream;
31
32public class Storage {
33    private static final String TAG = "CameraStorage";
34
35    public static final String DCIM =
36            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString();
37
38    public static final String DIRECTORY = DCIM + "/Camera";
39
40    // Match the code in MediaProvider.computeBucketValues().
41    public static final String BUCKET_ID =
42            String.valueOf(DIRECTORY.toLowerCase().hashCode());
43
44    public static final long UNAVAILABLE = -1L;
45    public static final long PREPARING = -2L;
46    public static final long UNKNOWN_SIZE = -3L;
47    public static final long LOW_STORAGE_THRESHOLD= 50000000;
48    public static final long PICTURE_SIZE = 1500000;
49
50    private static final int BUFSIZE = 4096;
51
52    public static Uri addImage(ContentResolver resolver, String title, long date,
53                Location location, int orientation, byte[] jpeg, int width, int height) {
54        // Save the image.
55        String path = generateFilepath(title);
56        FileOutputStream out = null;
57        try {
58            out = new FileOutputStream(path);
59            out.write(jpeg);
60        } catch (Exception e) {
61            Log.e(TAG, "Failed to write image", e);
62            return null;
63        } finally {
64            try {
65                out.close();
66            } catch (Exception e) {
67            }
68        }
69
70        // Insert into MediaStore.
71        ContentValues values = new ContentValues(9);
72        values.put(ImageColumns.TITLE, title);
73        values.put(ImageColumns.DISPLAY_NAME, title + ".jpg");
74        values.put(ImageColumns.DATE_TAKEN, date);
75        values.put(ImageColumns.MIME_TYPE, "image/jpeg");
76        values.put(ImageColumns.ORIENTATION, orientation);
77        values.put(ImageColumns.DATA, path);
78        values.put(ImageColumns.SIZE, jpeg.length);
79        values.put(ImageColumns.WIDTH, width);
80        values.put(ImageColumns.HEIGHT, height);
81
82        if (location != null) {
83            values.put(ImageColumns.LATITUDE, location.getLatitude());
84            values.put(ImageColumns.LONGITUDE, location.getLongitude());
85        }
86
87        Uri uri = null;
88        try {
89            uri = resolver.insert(Images.Media.EXTERNAL_CONTENT_URI, values);
90        } catch (Throwable th)  {
91            // This can happen when the external volume is already mounted, but
92            // MediaScanner has not notify MediaProvider to add that volume.
93            // The picture is still safe and MediaScanner will find it and
94            // insert it into MediaProvider. The only problem is that the user
95            // cannot click the thumbnail to review the picture.
96            Log.e(TAG, "Failed to write MediaStore" + th);
97        }
98        return uri;
99    }
100
101    public static String generateFilepath(String title) {
102        return DIRECTORY + '/' + title + ".jpg";
103    }
104
105    public static long getAvailableSpace() {
106        String state = Environment.getExternalStorageState();
107        Log.d(TAG, "External storage state=" + state);
108        if (Environment.MEDIA_CHECKING.equals(state)) {
109            return PREPARING;
110        }
111        if (!Environment.MEDIA_MOUNTED.equals(state)) {
112            return UNAVAILABLE;
113        }
114
115        File dir = new File(DIRECTORY);
116        dir.mkdirs();
117        if (!dir.isDirectory() || !dir.canWrite()) {
118            return UNAVAILABLE;
119        }
120
121        try {
122            StatFs stat = new StatFs(DIRECTORY);
123            return stat.getAvailableBlocks() * (long) stat.getBlockSize();
124        } catch (Exception e) {
125            Log.i(TAG, "Fail to access external storage", e);
126        }
127        return UNKNOWN_SIZE;
128    }
129
130    /**
131     * OSX requires plugged-in USB storage to have path /DCIM/NNNAAAAA to be
132     * imported. This is a temporary fix for bug#1655552.
133     */
134    public static void ensureOSXCompatible() {
135        File nnnAAAAA = new File(DCIM, "100ANDRO");
136        if (!(nnnAAAAA.exists() || nnnAAAAA.mkdirs())) {
137            Log.e(TAG, "Failed to create " + nnnAAAAA.getPath());
138        }
139    }
140}
141