• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 package com.android.devcamera;
17 
18 import android.content.ContentResolver;
19 import android.content.ContentValues;
20 import android.content.Context;
21 import android.content.SharedPreferences;
22 import android.os.SystemClock;
23 import android.provider.MediaStore;
24 import android.util.Log;
25 
26 import java.io.File;
27 import java.io.FileOutputStream;
28 import java.io.IOException;
29 import java.io.OutputStream;
30 import java.nio.ByteBuffer;
31 import java.nio.channels.FileChannel;
32 
33 /**
34  * This class has methods required to save a JPEG to disk as well as update the
35  * MediaStore database.
36  */
37 
38 
39 public class MediaSaver {
40     private static final String TAG = "Snappy_MediaSaver";
41     private static final String MY_PREFS_NAME = "SnappyPrefs";
42 
43     // MediaStore is slow/broken
44     private static final boolean UDPATE_MEDIA_STORE = true;
45 
46 
getNextInt(Context context, String id)47     public static int getNextInt(Context context, String id) {
48         SharedPreferences prefs = context.getSharedPreferences(MY_PREFS_NAME, Context.MODE_PRIVATE);
49         int i = prefs.getInt(id, 1);
50         SharedPreferences.Editor editor = prefs.edit();
51         editor.putInt(id, i+1);
52         editor.commit();
53         return i;
54     }
55 
56     /**
57      * @param context Application context.
58      * @param depthCloudData Depth cloud byte buffer.
59      */
saveDepth(Context context, ByteBuffer depthCloudData)60     public static String saveDepth(Context context, ByteBuffer depthCloudData) {
61         String filename = "";
62         try {
63             File file;
64             int i = getNextInt(context, "depthCounter");
65             filename = String.format("/sdcard/DCIM/Depth_%05d.img", i);
66             file = new File(filename);
67             if (!file.createNewFile()) {
68                 throw new IOException(filename);
69             }
70 
71             long t0 = SystemClock.uptimeMillis();
72             FileOutputStream fos = new FileOutputStream(file);
73             FileChannel channel = fos.getChannel();
74             int bytesWritten = 0;
75             int byteCount = 0;
76             while (depthCloudData.hasRemaining()) {
77                 byteCount = channel.write(depthCloudData);
78                 if (0 == byteCount) {
79                     throw new IOException(filename);
80                 } else {
81                     bytesWritten += byteCount;
82                 }
83             }
84             channel.close();
85             fos.flush();
86             fos.close();
87             long t1 = SystemClock.uptimeMillis();
88 
89             Log.v(TAG, String.format("Wrote Depth %d bytes as %s in %.3f seconds",
90                     bytesWritten, file, (t1 - t0) * 0.001));
91         } catch (IOException e) {
92             Log.e(TAG, "Error creating new file: ", e);
93         }
94         return filename;
95     }
96 
97     /**
98      * @param context Application context.
99      * @param jpegData JPEG byte stream.
100      */
saveJpeg(Context context, byte[] jpegData, ContentResolver resolver)101     public static String saveJpeg(Context context, byte[] jpegData, ContentResolver resolver) {
102         String filename = "";
103         try {
104             File file;
105             while (true) {
106                 int i = getNextInt(context, "counter");
107                 filename = String.format("/sdcard/DCIM/Camera/SNAP_%05d.JPG", i);
108                 file = new File(filename);
109                 if (file.createNewFile()) {
110                     break;
111                 }
112             }
113 
114             long t0 = SystemClock.uptimeMillis();
115             OutputStream os = new FileOutputStream(file);
116             os.write(jpegData);
117             os.flush();
118             os.close();
119             long t1 = SystemClock.uptimeMillis();
120 
121             // update MediaStore so photos apps can find photos right away.
122             if (UDPATE_MEDIA_STORE) {
123                 // really slow for some reason: MediaStore.Images.Media.insertImage(resolver, file.getAbsolutePath(), file.getName(), file.getName());
124                 insertImage(resolver, file);
125             }
126             long t2 = SystemClock.uptimeMillis();
127 
128             Log.v(TAG, String.format("Wrote JPEG %d bytes as %s in %.3f seconds; mediastore update = %.3f secs",
129                     jpegData.length, file, (t1 - t0) * 0.001, (t2 - t1) * 0.001)    );
130         } catch (IOException e) {
131             Log.e(TAG, "Error creating new file: ", e);
132         }
133         return filename;
134     }
135 
136 
137     // We use this instead of MediaStore.Images.Media.insertImage() because we want to add date metadata
insertImage(ContentResolver cr, File file)138     public static void insertImage(ContentResolver cr, File file) {
139 
140         ContentValues values = new ContentValues();
141         values.put(MediaStore.Images.Media.TITLE, file.getName());
142         values.put(MediaStore.Images.Media.DISPLAY_NAME, file.getName());
143         values.put(MediaStore.Images.Media.DESCRIPTION, file.getName());
144         values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
145         values.put(MediaStore.Images.Media.DATA, file.getAbsolutePath());
146         // Add the date meta data to ensure the image is added at the front of the gallery
147         values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis());
148         values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
149 
150         try {
151             cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
152         } catch (Exception e) {
153             Log.w(TAG, "Error updating media store for  " + file, e);
154         }
155     }
156 
157 }
158