10d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard/*
20d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard * Copyright (C) 2010 The Android Open Source Project
30d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard *
40d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard * Licensed under the Apache License, Version 2.0 (the "License");
50d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard * you may not use this file except in compliance with the License.
60d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard * You may obtain a copy of the License at
70d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard *
80d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard *      http://www.apache.org/licenses/LICENSE-2.0
90d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard *
100d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard * Unless required by applicable law or agreed to in writing, software
110d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard * distributed under the License is distributed on an "AS IS" BASIS,
120d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard * See the License for the specific language governing permissions and
140d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard * limitations under the License.
150d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard */
160d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
170d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardpackage com.android.gallery3d.filtershow.tools;
180d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
190d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.content.ContentResolver;
200d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.content.ContentValues;
210d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.content.Context;
2224d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroardimport android.content.Intent;
230d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.database.Cursor;
240d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.graphics.Bitmap;
250d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.net.Uri;
260d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.os.Environment;
27b3f62e4ed7a80010017dc3893460ca9043afb383ztenghuiimport android.provider.MediaStore;
280d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.provider.MediaStore.Images;
290d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.provider.MediaStore.Images.ImageColumns;
30014a111f10a7523415ca210bc6fe1e4f00183d31John Reckimport android.util.Log;
313b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroardimport android.widget.Toast;
320d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
33960e83bd57b6236f4eb7fff98aeb7082a48f6b97nicolasroardimport com.android.gallery3d.R;
342220b0e03ec1192b39d51c70cd70340b7269c3e0Earl Ouimport com.android.gallery3d.common.Utils;
356e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunkimport com.android.gallery3d.exif.ExifInterface;
3647886ac74f2874633d4c1284b91c33117f056581Ruben Brunkimport com.android.gallery3d.filtershow.FilterShowActivity;
37014a111f10a7523415ca210bc6fe1e4f00183d31John Reckimport com.android.gallery3d.filtershow.cache.ImageLoader;
38863b61f2ddd387473f588e2a9184eabb5a930096John Hofordimport com.android.gallery3d.filtershow.filters.FilterRepresentation;
39180277924bebf6b600ee5ce5adf9ff807a038570nicolasroardimport com.android.gallery3d.filtershow.filters.FiltersManager;
4047886ac74f2874633d4c1284b91c33117f056581Ruben Brunkimport com.android.gallery3d.filtershow.imageshow.MasterImage;
41077e718ecb6eb07997ad7c458d38eb21b3b2e6f9Ruben Brunkimport com.android.gallery3d.filtershow.pipeline.CachingPipeline;
42ce9ceff5776a9b0479c30cbeb2a9388b44df1865nicolasroardimport com.android.gallery3d.filtershow.pipeline.ImagePreset;
4324d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroardimport com.android.gallery3d.filtershow.pipeline.ProcessingService;
44014a111f10a7523415ca210bc6fe1e4f00183d31John Reckimport com.android.gallery3d.util.XmpUtilHelper;
450d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
460d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport java.io.File;
470d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport java.io.FileNotFoundException;
48b3f62e4ed7a80010017dc3893460ca9043afb383ztenghuiimport java.io.FilenameFilter;
490d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport java.io.IOException;
50014a111f10a7523415ca210bc6fe1e4f00183d31John Reckimport java.io.InputStream;
51077e718ecb6eb07997ad7c458d38eb21b3b2e6f9Ruben Brunkimport java.io.OutputStream;
520d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport java.sql.Date;
530d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport java.text.SimpleDateFormat;
542220b0e03ec1192b39d51c70cd70340b7269c3e0Earl Ouimport java.util.TimeZone;
550d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
560d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard/**
5724d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard * Handles saving edited photo
580d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard */
5924d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroardpublic class SaveImage {
6024d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard    private static final String LOGTAG = "SaveImage";
610d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
620d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    /**
6324d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard     * Callback for updates
640d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard     */
650d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    public interface Callback {
66ef4c2131c02f77d9fc508c7b26989a7f9b03862eJohn Hoford        void onPreviewSaved(Uri uri);
6724d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        void onProgress(int max, int current);
680d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
690d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
70b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    public interface ContentResolverQueryCallback {
710d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        void onCursorResult(Cursor cursor);
720d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
730d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
74b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk    private static final String TIME_STAMP_NAME = "_yyyyMMdd_HHmmss";
75b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk    private static final String PREFIX_PANO = "PANO";
76b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk    private static final String PREFIX_IMG = "IMG";
77b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk    private static final String POSTFIX_JPG = ".jpg";
78b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    private static final String AUX_DIR_NAME = ".aux";
79b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
80b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    private final Context mContext;
81b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    private final Uri mSourceUri;
82b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    private final Callback mCallback;
83b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    private final File mDestinationFile;
84b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    private final Uri mSelectedImageUri;
853b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard    private final Bitmap mPreviewImage;
8624d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard
8724d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard    private int mCurrentProcessingStep = 1;
8824d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard
8924d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard    public static final int MAX_PROCESSING_STEPS = 6;
9047886ac74f2874633d4c1284b91c33117f056581Ruben Brunk    public static final String DEFAULT_SAVE_DIRECTORY = "EditedOnlinePhotos";
91b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
92b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // In order to support the new edit-save behavior such that user won't see
93b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // the edited image together with the original image, we are adding a new
94b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // auxiliary directory for the edited image. Basically, the original image
95b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // will be hidden in that directory after edit and user will see the edited
96b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // image only.
97b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // Note that deletion on the edited image will also cause the deletion of
98b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // the original image under auxiliary directory.
99b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    //
100b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // There are several situations we need to consider:
101b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // 1. User edit local image local01.jpg. A local02.jpg will be created in the
102b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // same directory, and original image will be moved to auxiliary directory as
103b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // ./.aux/local02.jpg.
104b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // If user edit the local02.jpg, local03.jpg will be created in the local
105b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // directory and ./.aux/local02.jpg will be renamed to ./.aux/local03.jpg
106b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    //
107b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // 2. User edit remote image remote01.jpg from picassa or other server.
108b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // remoteSavedLocal01.jpg will be saved under proper local directory.
109b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // In remoteSavedLocal01.jpg, there will be a reference pointing to the
110b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // remote01.jpg. There will be no local copy of remote01.jpg.
111b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // If user edit remoteSavedLocal01.jpg, then a new remoteSavedLocal02.jpg
112b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // will be generated and still pointing to the remote01.jpg
113b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    //
114b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // 3. User delete any local image local.jpg.
115b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // Since the filenames are kept consistent in auxiliary directory, every
116b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // time a local.jpg get deleted, the files in auxiliary directory whose
117b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // names starting with "local." will be deleted.
118b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // This pattern will facilitate the multiple images deletion in the auxiliary
119b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    // directory.
1200d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
121b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    /**
122b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * @param context
123b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * @param sourceUri The Uri for the original image, which can be the hidden
124b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     *  image under the auxiliary directory or the same as selectedImageUri.
125b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * @param selectedImageUri The Uri for the image selected by the user.
126b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     *  In most cases, it is a content Uri for local image or remote image.
127b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * @param destination Destinaton File, if this is null, a new file will be
128b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     *  created under the same directory as selectedImageUri.
129b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * @param callback Let the caller know the saving has completed.
130b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * @return the newSourceUri
131b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     */
13224d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard    public SaveImage(Context context, Uri sourceUri, Uri selectedImageUri,
1333b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard                     File destination, Bitmap previewImage, Callback callback)  {
134b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        mContext = context;
135b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        mSourceUri = sourceUri;
136b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        mCallback = callback;
1373b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        mPreviewImage = previewImage;
1380ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard        if (destination == null) {
139b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            mDestinationFile = getNewFile(context, selectedImageUri);
1400ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard        } else {
141b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            mDestinationFile = destination;
1420ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard        }
1430ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard
144b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        mSelectedImageUri = selectedImageUri;
1450d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
1460d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
1470addfc7f6342184a67cdd8b5cc3872c6a5c87e55Doris Liu    public static File getFinalSaveDirectory(Context context, Uri sourceUri) {
14824d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        File saveDirectory = SaveImage.getSaveDirectory(context, sourceUri);
1490ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard        if ((saveDirectory == null) || !saveDirectory.canWrite()) {
1500ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard            saveDirectory = new File(Environment.getExternalStorageDirectory(),
15124d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard                    SaveImage.DEFAULT_SAVE_DIRECTORY);
1520ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard        }
15341a99ab167b83fc41d604c82ceda33a875883e98Doris Liu        // Create the directory if it doesn't exist
1546e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (!saveDirectory.exists())
1556e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            saveDirectory.mkdirs();
1560addfc7f6342184a67cdd8b5cc3872c6a5c87e55Doris Liu        return saveDirectory;
1570addfc7f6342184a67cdd8b5cc3872c6a5c87e55Doris Liu    }
1580ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard
1590addfc7f6342184a67cdd8b5cc3872c6a5c87e55Doris Liu    public static File getNewFile(Context context, Uri sourceUri) {
1600addfc7f6342184a67cdd8b5cc3872c6a5c87e55Doris Liu        File saveDirectory = getFinalSaveDirectory(context, sourceUri);
1610ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard        String filename = new SimpleDateFormat(TIME_STAMP_NAME).format(new Date(
1620ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard                System.currentTimeMillis()));
163b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk        if (hasPanoPrefix(context, sourceUri)) {
164b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk            return new File(saveDirectory, PREFIX_PANO + filename + POSTFIX_JPG);
165b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk        }
166b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk        return new File(saveDirectory, PREFIX_IMG + filename + POSTFIX_JPG);
1670ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard    }
1680ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard
169b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    /**
170b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * Remove the files in the auxiliary directory whose names are the same as
171b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * the source image.
172b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * @param contentResolver The application's contentResolver
173b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * @param srcContentUri The content Uri for the source image.
174b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     */
175b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    public static void deleteAuxFiles(ContentResolver contentResolver,
176b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            Uri srcContentUri) {
177b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        final String[] fullPath = new String[1];
178b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        String[] queryProjection = new String[] { ImageColumns.DATA };
179b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        querySourceFromContentResolver(contentResolver,
180b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                srcContentUri, queryProjection,
181b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                new ContentResolverQueryCallback() {
182b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                    @Override
183b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                    public void onCursorResult(Cursor cursor) {
184b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                        fullPath[0] = cursor.getString(0);
185b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                    }
186b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                }
187b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        );
188b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        if (fullPath[0] != null) {
189b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            // Construct the auxiliary directory given the source file's path.
190b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            // Then select and delete all the files starting with the same name
191b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            // under the auxiliary directory.
192b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            File currentFile = new File(fullPath[0]);
193b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
194b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            String filename = currentFile.getName();
195b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            int firstDotPos = filename.indexOf(".");
196b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            final String filenameNoExt = (firstDotPos == -1) ? filename :
197b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                filename.substring(0, firstDotPos);
198b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            File auxDir = getLocalAuxDirectory(currentFile);
199b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            if (auxDir.exists()) {
200b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                FilenameFilter filter = new FilenameFilter() {
201b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                    @Override
202b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                    public boolean accept(File dir, String name) {
203b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                        if (name.startsWith(filenameNoExt + ".")) {
204b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                            return true;
205b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                        } else {
206b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                            return false;
207b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                        }
208b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                    }
209b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                };
210b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
211b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                // Delete all auxiliary files whose name is matching the
212b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                // current local image.
213b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                File[] auxFiles = auxDir.listFiles(filter);
214b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                for (File file : auxFiles) {
215b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                    file.delete();
216b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                }
217b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            }
218b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        }
219b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    }
220b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
2216e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    public Object getPanoramaXMPData(Uri source, ImagePreset preset) {
2226e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        Object xmp = null;
2236e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (preset.isPanoramaSafe()) {
2246e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            InputStream is = null;
2256e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            try {
226b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                is = mContext.getContentResolver().openInputStream(source);
2276e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                xmp = XmpUtilHelper.extractXMPMeta(is);
2286e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            } catch (FileNotFoundException e) {
2296e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                Log.w(LOGTAG, "Failed to get XMP data from image: ", e);
2306e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            } finally {
2316e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                Utils.closeSilently(is);
2326e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
2336e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
2346e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return xmp;
2356e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    }
2366e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
2376e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    public boolean putPanoramaXMPData(File file, Object xmp) {
2386e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (xmp != null) {
2396e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return XmpUtilHelper.writeXMPMeta(file.getAbsolutePath(), xmp);
2406e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
2416e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return false;
2426e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    }
2436e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
2446e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    public ExifInterface getExifData(Uri source) {
2456e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        ExifInterface exif = new ExifInterface();
246b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        String mimeType = mContext.getContentResolver().getType(mSelectedImageUri);
24747886ac74f2874633d4c1284b91c33117f056581Ruben Brunk        if (mimeType == null) {
24847886ac74f2874633d4c1284b91c33117f056581Ruben Brunk            mimeType = ImageLoader.getMimeType(mSelectedImageUri);
24947886ac74f2874633d4c1284b91c33117f056581Ruben Brunk        }
2508bb4e1a036e67a3bf4f9cdb8f55d6f558189e5b9Ruben Brunk        if (mimeType.equals(ImageLoader.JPEG_MIME_TYPE)) {
2516e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            InputStream inStream = null;
2526e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            try {
253b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                inStream = mContext.getContentResolver().openInputStream(source);
2546e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                exif.readExif(inStream);
2556e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            } catch (FileNotFoundException e) {
2566e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                Log.w(LOGTAG, "Cannot find file: " + source, e);
2576e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            } catch (IOException e) {
2586e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                Log.w(LOGTAG, "Cannot read exif for: " + source, e);
2596e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            } finally {
2606e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                Utils.closeSilently(inStream);
2616e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
262014a111f10a7523415ca210bc6fe1e4f00183d31John Reck        }
2636e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return exif;
2646e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    }
2656e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
266077e718ecb6eb07997ad7c458d38eb21b3b2e6f9Ruben Brunk    public boolean putExifData(File file, ExifInterface exif, Bitmap image,
267077e718ecb6eb07997ad7c458d38eb21b3b2e6f9Ruben Brunk            int jpegCompressQuality) {
2686e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        boolean ret = false;
269077e718ecb6eb07997ad7c458d38eb21b3b2e6f9Ruben Brunk        OutputStream s = null;
2702220b0e03ec1192b39d51c70cd70340b7269c3e0Earl Ou        try {
271077e718ecb6eb07997ad7c458d38eb21b3b2e6f9Ruben Brunk            s = exif.getExifWriterStream(file.getAbsolutePath());
272077e718ecb6eb07997ad7c458d38eb21b3b2e6f9Ruben Brunk            image.compress(Bitmap.CompressFormat.JPEG,
273077e718ecb6eb07997ad7c458d38eb21b3b2e6f9Ruben Brunk                    (jpegCompressQuality > 0) ? jpegCompressQuality : 1, s);
274077e718ecb6eb07997ad7c458d38eb21b3b2e6f9Ruben Brunk            s.flush();
275077e718ecb6eb07997ad7c458d38eb21b3b2e6f9Ruben Brunk            s.close();
276077e718ecb6eb07997ad7c458d38eb21b3b2e6f9Ruben Brunk            s = null;
2776e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            ret = true;
2782220b0e03ec1192b39d51c70cd70340b7269c3e0Earl Ou        } catch (FileNotFoundException e) {
2796e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            Log.w(LOGTAG, "File not found: " + file.getAbsolutePath(), e);
2802220b0e03ec1192b39d51c70cd70340b7269c3e0Earl Ou        } catch (IOException e) {
2816e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            Log.w(LOGTAG, "Could not write exif: ", e);
282077e718ecb6eb07997ad7c458d38eb21b3b2e6f9Ruben Brunk        } finally {
283077e718ecb6eb07997ad7c458d38eb21b3b2e6f9Ruben Brunk            Utils.closeSilently(s);
2842220b0e03ec1192b39d51c70cd70340b7269c3e0Earl Ou        }
2856e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return ret;
286014a111f10a7523415ca210bc6fe1e4f00183d31John Reck    }
287014a111f10a7523415ca210bc6fe1e4f00183d31John Reck
288568b8d8bade4aac4bc598dff9b76ced159c533bfRuben Brunk    private Uri resetToOriginalImageIfNeeded(ImagePreset preset, boolean doAuxBackup) {
2896e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        Uri uri = null;
2908d90cb8d8629a56be63cff10035232f587c2d4bdztenghui        if (!preset.hasModifications()) {
2918d90cb8d8629a56be63cff10035232f587c2d4bdztenghui            // This can happen only when preset has no modification but save
2928d90cb8d8629a56be63cff10035232f587c2d4bdztenghui            // button is enabled, it means the file is loaded with filters in
2938d90cb8d8629a56be63cff10035232f587c2d4bdztenghui            // the XMP, then all the filters are removed or restore to default.
2948d90cb8d8629a56be63cff10035232f587c2d4bdztenghui            // In this case, when mSourceUri exists, rename it to the
2958d90cb8d8629a56be63cff10035232f587c2d4bdztenghui            // destination file.
2968d90cb8d8629a56be63cff10035232f587c2d4bdztenghui            File srcFile = getLocalFileFromUri(mContext, mSourceUri);
2978d90cb8d8629a56be63cff10035232f587c2d4bdztenghui            // If the source is not a local file, then skip this renaming and
2988d90cb8d8629a56be63cff10035232f587c2d4bdztenghui            // create a local copy as usual.
2998d90cb8d8629a56be63cff10035232f587c2d4bdztenghui            if (srcFile != null) {
3008d90cb8d8629a56be63cff10035232f587c2d4bdztenghui                srcFile.renameTo(mDestinationFile);
30108f4cc3988e54937f191e61588f50535df34712eztenghui                uri = SaveImage.linkNewFileToUri(mContext, mSelectedImageUri,
302568b8d8bade4aac4bc598dff9b76ced159c533bfRuben Brunk                        mDestinationFile, System.currentTimeMillis(), doAuxBackup);
3038d90cb8d8629a56be63cff10035232f587c2d4bdztenghui            }
3048d90cb8d8629a56be63cff10035232f587c2d4bdztenghui        }
30524d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        return uri;
30624d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard    }
30724d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard
30824d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard    private void resetProgress() {
30924d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        mCurrentProcessingStep = 0;
31024d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard    }
31124d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard
31224d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard    private void updateProgress() {
31324d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        if (mCallback != null) {
31424d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard            mCallback.onProgress(MAX_PROCESSING_STEPS, ++mCurrentProcessingStep);
31524d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        }
31624d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard    }
31724d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard
318863b61f2ddd387473f588e2a9184eabb5a930096John Hoford    private void updateExifData(ExifInterface exif, long time) {
319863b61f2ddd387473f588e2a9184eabb5a930096John Hoford        // Set tags
320863b61f2ddd387473f588e2a9184eabb5a930096John Hoford        exif.addDateTimeStampTag(ExifInterface.TAG_DATE_TIME, time,
321863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                TimeZone.getDefault());
322863b61f2ddd387473f588e2a9184eabb5a930096John Hoford        exif.setTag(exif.buildTag(ExifInterface.TAG_ORIENTATION,
323863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                ExifInterface.Orientation.TOP_LEFT));
324863b61f2ddd387473f588e2a9184eabb5a930096John Hoford        // Remove old thumbnail
325863b61f2ddd387473f588e2a9184eabb5a930096John Hoford        exif.removeCompressedThumbnail();
326863b61f2ddd387473f588e2a9184eabb5a930096John Hoford    }
327863b61f2ddd387473f588e2a9184eabb5a930096John Hoford
328863b61f2ddd387473f588e2a9184eabb5a930096John Hoford    public Uri processAndSaveImage(ImagePreset preset, boolean flatten,
329eeed64b1fbdafe5c91ce36b3c5488c003fbb8fabnicolasroard                                   int quality, float sizeFactor, boolean exit) {
33024d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard
331eeed64b1fbdafe5c91ce36b3c5488c003fbb8fabnicolasroard        Uri uri = null;
332eeed64b1fbdafe5c91ce36b3c5488c003fbb8fabnicolasroard        if (exit) {
333eeed64b1fbdafe5c91ce36b3c5488c003fbb8fabnicolasroard            uri = resetToOriginalImageIfNeeded(preset, !flatten);
334eeed64b1fbdafe5c91ce36b3c5488c003fbb8fabnicolasroard        }
33524d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        if (uri != null) {
33624d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard            return null;
33724d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        }
33824d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard
33924d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        resetProgress();
3408d90cb8d8629a56be63cff10035232f587c2d4bdztenghui
341182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk        boolean noBitmap = true;
342182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk        int num_tries = 0;
34347886ac74f2874633d4c1284b91c33117f056581Ruben Brunk        int sampleSize = 1;
344b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
345b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        // If necessary, move the source file into the auxiliary directory,
346b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        // newSourceUri is then pointing to the new location.
347b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        // If no file is moved, newSourceUri will be the same as mSourceUri.
348568b8d8bade4aac4bc598dff9b76ced159c533bfRuben Brunk        Uri newSourceUri = mSourceUri;
349863b61f2ddd387473f588e2a9184eabb5a930096John Hoford        if (!flatten) {
350568b8d8bade4aac4bc598dff9b76ced159c533bfRuben Brunk            newSourceUri = moveSrcToAuxIfNeeded(mSourceUri, mDestinationFile);
351568b8d8bade4aac4bc598dff9b76ced159c533bfRuben Brunk        }
35209169dd269f1a82efb83ea1cebf75abe4daabd26ztenghui
3533b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        Uri savedUri = mSelectedImageUri;
3543b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        if (mPreviewImage != null) {
355863b61f2ddd387473f588e2a9184eabb5a930096John Hoford            if (flatten) {
356863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                Object xmp = getPanoramaXMPData(newSourceUri, preset);
357863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                ExifInterface exif = getExifData(newSourceUri);
358863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                long time = System.currentTimeMillis();
359863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                updateExifData(exif, time);
360863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                if (putExifData(mDestinationFile, exif, mPreviewImage, quality)) {
361863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                    putPanoramaXMPData(mDestinationFile, xmp);
362863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                    ContentValues values = getContentValues(mContext, mSelectedImageUri, mDestinationFile, time);
363863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                    Object result = mContext.getContentResolver().insert(
364863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                            Images.Media.EXTERNAL_CONTENT_URI, values);
365863b61f2ddd387473f588e2a9184eabb5a930096John Hoford
366863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                }
367863b61f2ddd387473f588e2a9184eabb5a930096John Hoford            } else {
368863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                Object xmp = getPanoramaXMPData(newSourceUri, preset);
369863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                ExifInterface exif = getExifData(newSourceUri);
370863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                long time = System.currentTimeMillis();
371863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                updateExifData(exif, time);
372863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                // If we succeed in writing the bitmap as a jpeg, return a uri.
373863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                if (putExifData(mDestinationFile, exif, mPreviewImage, quality)) {
374863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                    putPanoramaXMPData(mDestinationFile, xmp);
375863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                    // mDestinationFile will save the newSourceUri info in the XMP.
376863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                    if (!flatten) {
377863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                        XmpPresets.writeFilterXMP(mContext, newSourceUri,
378863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                                mDestinationFile, preset);
379863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                    }
380863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                    // After this call, mSelectedImageUri will be actually
381863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                    // pointing at the new file mDestinationFile.
382863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                    savedUri = SaveImage.linkNewFileToUri(mContext, mSelectedImageUri,
383863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                            mDestinationFile, time, !flatten);
384863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                }
3853b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard            }
386ef4c2131c02f77d9fc508c7b26989a7f9b03862eJohn Hoford            if (mCallback != null) {
387ef4c2131c02f77d9fc508c7b26989a7f9b03862eJohn Hoford                mCallback.onPreviewSaved(savedUri);
388ef4c2131c02f77d9fc508c7b26989a7f9b03862eJohn Hoford            }
3893b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        }
3903b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard
391182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk        // Stopgap fix for low-memory devices.
3926e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        while (noBitmap) {
393182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk            try {
39424d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard                updateProgress();
395182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk                // Try to do bitmap operations, downsample if low-memory
39647886ac74f2874633d4c1284b91c33117f056581Ruben Brunk                Bitmap bitmap = ImageLoader.loadOrientedBitmapWithBackouts(mContext, newSourceUri,
39747886ac74f2874633d4c1284b91c33117f056581Ruben Brunk                        sampleSize);
398182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk                if (bitmap == null) {
399182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk                    return null;
400182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk                }
40155d6abe58c3a7574a5d76c68ec5c21848848e399nicolasroard                if (sizeFactor != 1f) {
40255d6abe58c3a7574a5d76c68ec5c21848848e399nicolasroard                    // if we have a valid size
40355d6abe58c3a7574a5d76c68ec5c21848848e399nicolasroard                    int w = (int) (bitmap.getWidth() * sizeFactor);
40455d6abe58c3a7574a5d76c68ec5c21848848e399nicolasroard                    int h = (int) (bitmap.getHeight() * sizeFactor);
40597ad2bdcb39c0484dafb08f4a7f45bcd1a3f4f9dnicolasroard                    if (w == 0 || h == 0) {
40697ad2bdcb39c0484dafb08f4a7f45bcd1a3f4f9dnicolasroard                        w = 1;
40797ad2bdcb39c0484dafb08f4a7f45bcd1a3f4f9dnicolasroard                        h = 1;
40897ad2bdcb39c0484dafb08f4a7f45bcd1a3f4f9dnicolasroard                    }
40955d6abe58c3a7574a5d76c68ec5c21848848e399nicolasroard                    bitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
41055d6abe58c3a7574a5d76c68ec5c21848848e399nicolasroard                }
41124d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard                updateProgress();
41247886ac74f2874633d4c1284b91c33117f056581Ruben Brunk                CachingPipeline pipeline = new CachingPipeline(FiltersManager.getManager(),
41347886ac74f2874633d4c1284b91c33117f056581Ruben Brunk                        "Saving");
41424d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard
415180277924bebf6b600ee5ce5adf9ff807a038570nicolasroard                bitmap = pipeline.renderFinalImage(bitmap, preset);
41624d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard                updateProgress();
417182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk
41809169dd269f1a82efb83ea1cebf75abe4daabd26ztenghui                Object xmp = getPanoramaXMPData(newSourceUri, preset);
41909169dd269f1a82efb83ea1cebf75abe4daabd26ztenghui                ExifInterface exif = getExifData(newSourceUri);
4206e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                long time = System.currentTimeMillis();
421863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                updateProgress();
422aee6dffcadf2a5387fde1c9c123698f602d9bb18Ruben Brunk
423863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                updateExifData(exif, time);
42409169dd269f1a82efb83ea1cebf75abe4daabd26ztenghui                updateProgress();
42509169dd269f1a82efb83ea1cebf75abe4daabd26ztenghui
4266e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                // If we succeed in writing the bitmap as a jpeg, return a uri.
427077e718ecb6eb07997ad7c458d38eb21b3b2e6f9Ruben Brunk                if (putExifData(mDestinationFile, exif, bitmap, quality)) {
428b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                    putPanoramaXMPData(mDestinationFile, xmp);
42909169dd269f1a82efb83ea1cebf75abe4daabd26ztenghui                    // mDestinationFile will save the newSourceUri info in the XMP.
430863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                    if (!flatten) {
431863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                        XmpPresets.writeFilterXMP(mContext, newSourceUri,
432863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                                mDestinationFile, preset);
433863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                        uri = updateFile(mContext, savedUri, mDestinationFile, time);
434863b61f2ddd387473f588e2a9184eabb5a930096John Hoford
435863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                    } else {
43609169dd269f1a82efb83ea1cebf75abe4daabd26ztenghui
437863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                        ContentValues values = getContentValues(mContext, mSelectedImageUri, mDestinationFile, time);
438863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                        Object result = mContext.getContentResolver().insert(
439863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                                Images.Media.EXTERNAL_CONTENT_URI, values);
440863b61f2ddd387473f588e2a9184eabb5a930096John Hoford                    }
441182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk                }
44224d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard                updateProgress();
443b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
444182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk                noBitmap = false;
44524d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard            } catch (OutOfMemoryError e) {
446182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk                // Try 5 times before failing for good.
447182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk                if (++num_tries >= 5) {
448182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk                    throw e;
449182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk                }
450182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk                System.gc();
45147886ac74f2874633d4c1284b91c33117f056581Ruben Brunk                sampleSize *= 2;
45224d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard                resetProgress();
453aeb7d79d2a35f534276bc6bf8128349f9768ae6bRuben Brunk            }
454014a111f10a7523415ca210bc6fe1e4f00183d31John Reck        }
455182659f7e3b04af88198cc3004af96e4944e32e5Ruben Brunk        return uri;
4560d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
4570d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
458b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    /**
459b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     *  Move the source file to auxiliary directory if needed and return the Uri
460eb2950384846a3797e13b04765f65df70d80982eztenghui     *  pointing to this new source file. If any file error happens, then just
461eb2950384846a3797e13b04765f65df70d80982eztenghui     *  don't move into the auxiliary directory.
462b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * @param srcUri Uri to the source image.
463b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * @param dstFile Providing the destination file info to help to build the
464b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     *  auxiliary directory and new source file's name.
465b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * @return the newSourceUri pointing to the new source image.
466b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     */
467b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    private Uri moveSrcToAuxIfNeeded(Uri srcUri, File dstFile) {
4688d90cb8d8629a56be63cff10035232f587c2d4bdztenghui        File srcFile = getLocalFileFromUri(mContext, srcUri);
469b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        if (srcFile == null) {
470b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            Log.d(LOGTAG, "Source file is not a local file, no update.");
471b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            return srcUri;
472b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        }
473b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
474b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        // Get the destination directory and create the auxilliary directory
475b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        // if necessary.
476b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        File auxDiretory = getLocalAuxDirectory(dstFile);
477b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        if (!auxDiretory.exists()) {
478eb2950384846a3797e13b04765f65df70d80982eztenghui            boolean success = auxDiretory.mkdirs();
479eb2950384846a3797e13b04765f65df70d80982eztenghui            if (!success) {
480eb2950384846a3797e13b04765f65df70d80982eztenghui                return srcUri;
481eb2950384846a3797e13b04765f65df70d80982eztenghui            }
482b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        }
483b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
484b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        // Make sure there is a .nomedia file in the auxiliary directory, such
485b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        // that MediaScanner will not report those files under this directory.
486b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        File noMedia = new File(auxDiretory, ".nomedia");
487b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        if (!noMedia.exists()) {
488b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            try {
489b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                noMedia.createNewFile();
490b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            } catch (IOException e) {
491b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                Log.e(LOGTAG, "Can't create the nomedia");
492b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                return srcUri;
493b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            }
494b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        }
495b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        // We are using the destination file name such that photos sitting in
496b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        // the auxiliary directory are matching the parent directory.
497b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        File newSrcFile = new File(auxDiretory, dstFile.getName());
498441d7a8930360d1c043daabd76a6599f2a8a60baJohn Hoford        // Maintain the suffix during move
499441d7a8930360d1c043daabd76a6599f2a8a60baJohn Hoford        String to = newSrcFile.getName();
500441d7a8930360d1c043daabd76a6599f2a8a60baJohn Hoford        String from = srcFile.getName();
501441d7a8930360d1c043daabd76a6599f2a8a60baJohn Hoford        to = to.substring(to.lastIndexOf("."));
502441d7a8930360d1c043daabd76a6599f2a8a60baJohn Hoford        from = from.substring(from.lastIndexOf("."));
503441d7a8930360d1c043daabd76a6599f2a8a60baJohn Hoford
504441d7a8930360d1c043daabd76a6599f2a8a60baJohn Hoford        if (!to.equals(from)) {
505441d7a8930360d1c043daabd76a6599f2a8a60baJohn Hoford            String name = dstFile.getName();
506441d7a8930360d1c043daabd76a6599f2a8a60baJohn Hoford            name = name.substring(0, name.lastIndexOf(".")) + from;
507441d7a8930360d1c043daabd76a6599f2a8a60baJohn Hoford            newSrcFile = new File(auxDiretory, name);
508441d7a8930360d1c043daabd76a6599f2a8a60baJohn Hoford        }
509b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
510b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        if (!newSrcFile.exists()) {
511eb2950384846a3797e13b04765f65df70d80982eztenghui            boolean success = srcFile.renameTo(newSrcFile);
512eb2950384846a3797e13b04765f65df70d80982eztenghui            if (!success) {
513eb2950384846a3797e13b04765f65df70d80982eztenghui                return srcUri;
514eb2950384846a3797e13b04765f65df70d80982eztenghui            }
515b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        }
516b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
517b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        return Uri.fromFile(newSrcFile);
518b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
519b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    }
520b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
521b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    private static File getLocalAuxDirectory(File dstFile) {
522b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        File dstDirectory = dstFile.getParentFile();
523b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        File auxDiretory = new File(dstDirectory + "/" + AUX_DIR_NAME);
524b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        return auxDiretory;
525b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    }
526afa8ed9d46e760d4b0c0331cfcb4bb49ef6ba280John Hoford
52747886ac74f2874633d4c1284b91c33117f056581Ruben Brunk    public static Uri makeAndInsertUri(Context context, Uri sourceUri) {
52847886ac74f2874633d4c1284b91c33117f056581Ruben Brunk        long time = System.currentTimeMillis();
52947886ac74f2874633d4c1284b91c33117f056581Ruben Brunk        String filename = new SimpleDateFormat(TIME_STAMP_NAME).format(new Date(time));
53047886ac74f2874633d4c1284b91c33117f056581Ruben Brunk        File saveDirectory = getFinalSaveDirectory(context, sourceUri);
53147886ac74f2874633d4c1284b91c33117f056581Ruben Brunk        File file = new File(saveDirectory, filename  + ".JPG");
532568b8d8bade4aac4bc598dff9b76ced159c533bfRuben Brunk        return linkNewFileToUri(context, sourceUri, file, time, false);
53347886ac74f2874633d4c1284b91c33117f056581Ruben Brunk    }
53447886ac74f2874633d4c1284b91c33117f056581Ruben Brunk
53547886ac74f2874633d4c1284b91c33117f056581Ruben Brunk    public static void saveImage(ImagePreset preset, final FilterShowActivity filterShowActivity,
53647886ac74f2874633d4c1284b91c33117f056581Ruben Brunk            File destination) {
53747886ac74f2874633d4c1284b91c33117f056581Ruben Brunk        Uri selectedImageUri = filterShowActivity.getSelectedImageUri();
53824d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        Uri sourceImageUri = MasterImage.getImage().getUri();
539863b61f2ddd387473f588e2a9184eabb5a930096John Hoford        boolean flatten = false;
540863b61f2ddd387473f588e2a9184eabb5a930096John Hoford        if (preset.contains(FilterRepresentation.TYPE_TINYPLANET)){
541863b61f2ddd387473f588e2a9184eabb5a930096John Hoford            flatten = true;
542863b61f2ddd387473f588e2a9184eabb5a930096John Hoford        }
54324d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        Intent processIntent = ProcessingService.getSaveIntent(filterShowActivity, preset,
544eeed64b1fbdafe5c91ce36b3c5488c003fbb8fabnicolasroard                destination, selectedImageUri, sourceImageUri, flatten, 90, 1f, true);
54547886ac74f2874633d4c1284b91c33117f056581Ruben Brunk
54624d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        filterShowActivity.startService(processIntent);
54747886ac74f2874633d4c1284b91c33117f056581Ruben Brunk
54824d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        if (!filterShowActivity.isSimpleEditAction()) {
549960e83bd57b6236f4eb7fff98aeb7082a48f6b97nicolasroard            String toastMessage = filterShowActivity.getResources().getString(
550960e83bd57b6236f4eb7fff98aeb7082a48f6b97nicolasroard                    R.string.save_and_processing);
551960e83bd57b6236f4eb7fff98aeb7082a48f6b97nicolasroard            Toast.makeText(filterShowActivity,
552960e83bd57b6236f4eb7fff98aeb7082a48f6b97nicolasroard                    toastMessage,
553960e83bd57b6236f4eb7fff98aeb7082a48f6b97nicolasroard                    Toast.LENGTH_SHORT).show();
55424d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        }
55524d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard    }
55647886ac74f2874633d4c1284b91c33117f056581Ruben Brunk
55747886ac74f2874633d4c1284b91c33117f056581Ruben Brunk    public static void querySource(Context context, Uri sourceUri, String[] projection,
5580d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            ContentResolverQueryCallback callback) {
5590d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        ContentResolver contentResolver = context.getContentResolver();
560b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        querySourceFromContentResolver(contentResolver, sourceUri, projection, callback);
561b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    }
562b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
563b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    private static void querySourceFromContentResolver(
564b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            ContentResolver contentResolver, Uri sourceUri, String[] projection,
565b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            ContentResolverQueryCallback callback) {
5660d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        Cursor cursor = null;
5670d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        try {
5680d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            cursor = contentResolver.query(sourceUri, projection, null, null,
5690d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                    null);
5700d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            if ((cursor != null) && cursor.moveToNext()) {
5710d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                callback.onCursorResult(cursor);
5720d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            }
5730d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        } catch (Exception e) {
5740d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            // Ignore error for lacking the data column from the source.
5750d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        } finally {
5760d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            if (cursor != null) {
5770d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                cursor.close();
5780d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            }
5790d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        }
5800d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
5810d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
5820ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard    private static File getSaveDirectory(Context context, Uri sourceUri) {
5838d90cb8d8629a56be63cff10035232f587c2d4bdztenghui        File file = getLocalFileFromUri(context, sourceUri);
584b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        if (file != null) {
585b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            return file.getParentFile();
586b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        } else {
587b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            return null;
588b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        }
589b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    }
5900d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
591b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui    /**
592b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * Construct a File object based on the srcUri.
593b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * @return The file object. Return null if srcUri is invalid or not a local
594b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     * file.
595b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui     */
5968d90cb8d8629a56be63cff10035232f587c2d4bdztenghui    private static File getLocalFileFromUri(Context context, Uri srcUri) {
597b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        if (srcUri == null) {
598b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            Log.e(LOGTAG, "srcUri is null.");
599b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            return null;
600b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        }
601b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
602b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        String scheme = srcUri.getScheme();
603b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        if (scheme == null) {
604b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            Log.e(LOGTAG, "scheme is null.");
605b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            return null;
606b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        }
607b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
608b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        final File[] file = new File[1];
609b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        // sourceUri can be a file path or a content Uri, it need to be handled
610b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        // differently.
611b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {
612b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            if (srcUri.getAuthority().equals(MediaStore.AUTHORITY)) {
613b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                querySource(context, srcUri, new String[] {
614b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                        ImageColumns.DATA
615b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                },
616b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                        new ContentResolverQueryCallback() {
617b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui
618b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                            @Override
619b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                            public void onCursorResult(Cursor cursor) {
620b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                                file[0] = new File(cursor.getString(0));
621b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                            }
622b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui                        });
623b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            }
624b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        } else if (scheme.equals(ContentResolver.SCHEME_FILE)) {
625b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui            file[0] = new File(srcUri.getPath());
626b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        }
627b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        return file[0];
6280d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
6290d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
6300d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    /**
631b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk     * Gets the actual filename for a Uri from Gallery's ContentProvider.
632b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk     */
633b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk    private static String getTrueFilename(Context context, Uri src) {
634b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk        if (context == null || src == null) {
635b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk            return null;
636b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk        }
637b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk        final String[] trueName = new String[1];
638b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk        querySource(context, src, new String[] {
639b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk                ImageColumns.DATA
640b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk        }, new ContentResolverQueryCallback() {
641b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk            @Override
642b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk            public void onCursorResult(Cursor cursor) {
643b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk                trueName[0] = new File(cursor.getString(0)).getName();
644b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk            }
645b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk        });
646b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk        return trueName[0];
647b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk    }
648b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk
649b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk    /**
650b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk     * Checks whether the true filename has the panorama image prefix.
651b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk     */
652b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk    private static boolean hasPanoPrefix(Context context, Uri src) {
653b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk        String name = getTrueFilename(context, src);
654b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk        return name != null && name.startsWith(PREFIX_PANO);
655b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk    }
656b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk
657b619ded0b604c5b34e2ecdb3f082cc34bc3ab012Ruben Brunk    /**
65808f4cc3988e54937f191e61588f50535df34712eztenghui     * If the <code>sourceUri</code> is a local content Uri, update the
65908f4cc3988e54937f191e61588f50535df34712eztenghui     * <code>sourceUri</code> to point to the <code>file</code>.
66008f4cc3988e54937f191e61588f50535df34712eztenghui     * At the same time, the old file <code>sourceUri</code> used to point to
66108f4cc3988e54937f191e61588f50535df34712eztenghui     * will be removed if it is local.
66208f4cc3988e54937f191e61588f50535df34712eztenghui     * If the <code>sourceUri</code> is not a local content Uri, then the
66308f4cc3988e54937f191e61588f50535df34712eztenghui     * <code>file</code> will be inserted as a new content Uri.
66408f4cc3988e54937f191e61588f50535df34712eztenghui     * @return the final Uri referring to the <code>file</code>.
6650d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard     */
66608f4cc3988e54937f191e61588f50535df34712eztenghui    public static Uri linkNewFileToUri(Context context, Uri sourceUri,
667568b8d8bade4aac4bc598dff9b76ced159c533bfRuben Brunk            File file, long time, boolean deleteOriginal) {
66809169dd269f1a82efb83ea1cebf75abe4daabd26ztenghui        File oldSelectedFile = getLocalFileFromUri(context, sourceUri);
6693b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        final ContentValues values = getContentValues(context, sourceUri, file, time);
6703b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard
6713b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        Uri result = sourceUri;
6723b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard
6733b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        // In the case of incoming Uri is just a local file Uri (like a cached
6743b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        // file), we can't just update the Uri. We have to create a new Uri.
6753b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        boolean fileUri = isFileUri(sourceUri);
6763b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard
6773b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        if (fileUri || oldSelectedFile == null || !deleteOriginal) {
6783b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard            result = context.getContentResolver().insert(
6793b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard                    Images.Media.EXTERNAL_CONTENT_URI, values);
6803b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        } else {
6813b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard            context.getContentResolver().update(sourceUri, values, null, null);
6823b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard            if (oldSelectedFile.exists()) {
6833b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard                oldSelectedFile.delete();
6843b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard            }
6853b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        }
6863b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        return result;
6873b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard    }
6883b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard
6893b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard    public static Uri updateFile(Context context, Uri sourceUri, File file, long time) {
6903b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        final ContentValues values = getContentValues(context, sourceUri, file, time);
6913b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        context.getContentResolver().update(sourceUri, values, null, null);
6923b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        return sourceUri;
6933b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard    }
6943b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard
6953b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard    private static ContentValues getContentValues(Context context, Uri sourceUri,
6963b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard                                                  File file, long time) {
6970d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        final ContentValues values = new ContentValues();
69809169dd269f1a82efb83ea1cebf75abe4daabd26ztenghui
69909169dd269f1a82efb83ea1cebf75abe4daabd26ztenghui        time /= 1000;
700b3f62e4ed7a80010017dc3893460ca9043afb383ztenghui        values.put(Images.Media.TITLE, file.getName());
7010d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        values.put(Images.Media.DISPLAY_NAME, file.getName());
7020d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        values.put(Images.Media.MIME_TYPE, "image/jpeg");
7036e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        values.put(Images.Media.DATE_TAKEN, time);
70447886ac74f2874633d4c1284b91c33117f056581Ruben Brunk        values.put(Images.Media.DATE_MODIFIED, time);
7056e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        values.put(Images.Media.DATE_ADDED, time);
7060d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        values.put(Images.Media.ORIENTATION, 0);
7070d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        values.put(Images.Media.DATA, file.getAbsolutePath());
7080d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        values.put(Images.Media.SIZE, file.length());
709aa22947b6f0714b73a78a28fb1217f7c5f4f663dztenghui        // This is a workaround to trigger the MediaProvider to re-generate the
710aa22947b6f0714b73a78a28fb1217f7c5f4f663dztenghui        // thumbnail.
711aa22947b6f0714b73a78a28fb1217f7c5f4f663dztenghui        values.put(Images.Media.MINI_THUMB_MAGIC, 0);
7120d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
713014a111f10a7523415ca210bc6fe1e4f00183d31John Reck        final String[] projection = new String[] {
7140d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                ImageColumns.DATE_TAKEN,
7150d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                ImageColumns.LATITUDE, ImageColumns.LONGITUDE,
7160d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        };
7173b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard
71824d6ec7beb37eb3a5449f1fa49b4adb123391d24nicolasroard        SaveImage.querySource(context, sourceUri, projection,
7193b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard                new ContentResolverQueryCallback() {
7200d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
7216e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    @Override
7226e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    public void onCursorResult(Cursor cursor) {
7236e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        values.put(Images.Media.DATE_TAKEN, cursor.getLong(0));
7246e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
7256e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        double latitude = cursor.getDouble(1);
7266e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        double longitude = cursor.getDouble(2);
7276e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        // TODO: Change || to && after the default location
7286e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        // issue is fixed.
7296e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        if ((latitude != 0f) || (longitude != 0f)) {
7306e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                            values.put(Images.Media.LATITUDE, latitude);
7316e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                            values.put(Images.Media.LONGITUDE, longitude);
7326e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        }
7336e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    }
7346e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                });
7353b311c3ffc7e9c6b7f5a89337787a656d6e10dbcnicolasroard        return values;
7360d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
7370ee91a2b74808fa3f51d370daaddf99f588d72efnicolasroard
738eb2950384846a3797e13b04765f65df70d80982eztenghui    /**
739eb2950384846a3797e13b04765f65df70d80982eztenghui     * @param sourceUri
740eb2950384846a3797e13b04765f65df70d80982eztenghui     * @return true if the sourceUri is a local file Uri.
741eb2950384846a3797e13b04765f65df70d80982eztenghui     */
742eb2950384846a3797e13b04765f65df70d80982eztenghui    private static boolean isFileUri(Uri sourceUri) {
743eb2950384846a3797e13b04765f65df70d80982eztenghui        String scheme = sourceUri.getScheme();
744eb2950384846a3797e13b04765f65df70d80982eztenghui        if (scheme != null && scheme.equals(ContentResolver.SCHEME_FILE)) {
745eb2950384846a3797e13b04765f65df70d80982eztenghui            return true;
746eb2950384846a3797e13b04765f65df70d80982eztenghui        }
747eb2950384846a3797e13b04765f65df70d80982eztenghui        return false;
748eb2950384846a3797e13b04765f65df70d80982eztenghui    }
749eb2950384846a3797e13b04765f65df70d80982eztenghui
7500d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard}
751