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