• 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.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