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