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.photoeditor; 18 19 import android.content.ContentResolver; 20 import android.content.ContentValues; 21 import android.content.Context; 22 import android.database.Cursor; 23 import android.graphics.Bitmap.CompressFormat; 24 import android.net.Uri; 25 import android.os.AsyncTask; 26 import android.os.Environment; 27 import android.provider.MediaStore.Images; 28 import android.provider.MediaStore.Images.ImageColumns; 29 import android.widget.Toast; 30 31 import java.io.File; 32 import java.sql.Date; 33 import java.text.SimpleDateFormat; 34 35 /** 36 * Asynchronous task for loading source photo in target dimensions and saving edits as a new copy. 37 */ 38 public class SaveCopyTask extends AsyncTask<Photo, Void, Uri> { 39 40 /** 41 * Callback for the completed asynchronous task. 42 */ 43 public interface Callback { 44 onComplete(Uri uri)45 void onComplete(Uri uri); 46 } 47 48 private static final String TIME_STAMP_NAME = "'IMG'_yyyyMMdd_HHmmss"; 49 private static final int INDEX_DATE_TAKEN = 0; 50 private static final int INDEX_LATITUDE = 1; 51 private static final int INDEX_LONGITUDE = 2; 52 53 private static final String[] IMAGE_PROJECTION = new String[] { 54 ImageColumns.DATE_TAKEN, 55 ImageColumns.LATITUDE, 56 ImageColumns.LONGITUDE, 57 }; 58 59 private final Context context; 60 private final Uri sourceUri; 61 private final Callback callback; 62 private final String saveFileName; 63 SaveCopyTask(Context context, Uri sourceUri, Callback callback)64 public SaveCopyTask(Context context, Uri sourceUri, Callback callback) { 65 this.context = context; 66 this.sourceUri = sourceUri; 67 this.callback = callback; 68 69 saveFileName = new SimpleDateFormat(TIME_STAMP_NAME).format( 70 new Date(System.currentTimeMillis())); 71 } 72 73 /** 74 * The task should be executed with one given photo to be saved. 75 */ 76 @Override doInBackground(Photo... params)77 protected Uri doInBackground(Photo... params) { 78 // TODO: Support larger dimensions for photo saving. 79 if (params[0] == null) { 80 return null; 81 } 82 Photo photo = params[0]; 83 File file = save(photo); 84 Uri uri = (file != null) ? insertContent(file) : null; 85 photo.clear(); 86 return uri; 87 } 88 89 @Override onPostExecute(Uri result)90 protected void onPostExecute(Uri result) { 91 String message = (result == null) ? context.getString(R.string.saving_failure) 92 : context.getString(R.string.photo_saved, saveFileName); 93 Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); 94 95 callback.onComplete(result); 96 } 97 save(Photo photo)98 private File save(Photo photo) { 99 String directory = Environment.getExternalStorageDirectory().toString() + "/" 100 + context.getString(R.string.edited_photo_bucket_name); 101 102 return new BitmapUtils(context).saveBitmap( 103 photo.bitmap(), directory, saveFileName, CompressFormat.JPEG); 104 } 105 106 /** 107 * Insert the content (saved file) with proper source photo properties. 108 */ insertContent(File file)109 private Uri insertContent(File file) { 110 long now = System.currentTimeMillis() / 1000; 111 long dateTaken = now; 112 double latitude = 0f; 113 double longitude = 0f; 114 115 ContentResolver contentResolver = context.getContentResolver(); 116 Cursor cursor = contentResolver.query( 117 sourceUri, IMAGE_PROJECTION, null, null, null); 118 if ((cursor != null) && cursor.moveToNext()) { 119 dateTaken = cursor.getLong(INDEX_DATE_TAKEN); 120 latitude = cursor.getDouble(INDEX_LATITUDE); 121 longitude = cursor.getDouble(INDEX_LONGITUDE); 122 } 123 124 ContentValues values = new ContentValues(); 125 values.put(Images.Media.TITLE, saveFileName); 126 values.put(Images.Media.DISPLAY_NAME, saveFileName); 127 values.put(Images.Media.MIME_TYPE, "image/jpeg"); 128 values.put(Images.Media.DATE_TAKEN, dateTaken); 129 values.put(Images.Media.DATE_MODIFIED, now); 130 values.put(Images.Media.DATE_ADDED, now); 131 values.put(Images.Media.ORIENTATION, 0); 132 values.put(Images.Media.DATA, file.getAbsolutePath()); 133 values.put(Images.Media.SIZE, file.length()); 134 135 // TODO: Change || to && after the default location issue is fixed. 136 if ((latitude != 0f) || (longitude != 0f)) { 137 values.put(Images.Media.LATITUDE, latitude); 138 values.put(Images.Media.LONGITUDE, longitude); 139 } 140 return contentResolver.insert(Images.Media.EXTERNAL_CONTENT_URI, values); 141 } 142 } 143