Home | History | Annotate | Download | only in data
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.camera.data;
     18 
     19 import android.app.ProgressDialog;
     20 import android.content.ContentValues;
     21 import android.content.Context;
     22 import android.os.AsyncTask;
     23 import android.provider.MediaStore.Images;
     24 
     25 import com.android.camera.data.LocalMediaData.PhotoData;
     26 import com.android.camera.debug.Log;
     27 import com.android.camera.exif.ExifInterface;
     28 import com.android.camera.exif.ExifTag;
     29 import com.android.camera2.R;
     30 
     31 import java.io.File;
     32 import java.io.FileNotFoundException;
     33 import java.io.IOException;
     34 
     35 /**
     36  * RotationTask can be used to rotate a {@link LocalData} by updating the exif
     37  * data from jpeg file. Note that only {@link PhotoData}  can be rotated.
     38  */
     39 public class RotationTask extends AsyncTask<LocalData, Void, LocalData> {
     40     private static final Log.Tag TAG = new Log.Tag("RotationTask");
     41     private final Context mContext;
     42     private final LocalDataAdapter mAdapter;
     43     private final int mCurrentDataId;
     44     private final boolean mClockwise;
     45     private ProgressDialog mProgress;
     46 
     47     public RotationTask(Context context, LocalDataAdapter adapter,
     48             int currentDataId, boolean clockwise) {
     49         mContext = context;
     50         mAdapter = adapter;
     51         mCurrentDataId = currentDataId;
     52         mClockwise = clockwise;
     53     }
     54 
     55     @Override
     56     protected void onPreExecute() {
     57         // Show a progress bar since the rotation could take long.
     58         mProgress = new ProgressDialog(mContext);
     59         int titleStringId = mClockwise ? R.string.rotate_right : R.string.rotate_left;
     60         mProgress.setTitle(mContext.getString(titleStringId));
     61         mProgress.setMessage(mContext.getString(R.string.please_wait));
     62         mProgress.setCancelable(false);
     63         mProgress.show();
     64     }
     65 
     66     @Override
     67     protected LocalData doInBackground(LocalData... data) {
     68         return rotateInJpegExif(data[0]);
     69     }
     70 
     71     /**
     72      * Rotates the image by updating the exif. Done in background thread.
     73      * The worst case is the whole file needed to be re-written with
     74      * modified exif data.
     75      *
     76      * @return A new {@link LocalData} object which containing the new info.
     77      */
     78     private LocalData rotateInJpegExif(LocalData data) {
     79         if (!(data instanceof PhotoData)) {
     80             Log.w(TAG, "Rotation can only happen on PhotoData.");
     81             return null;
     82         }
     83 
     84         PhotoData imageData = (PhotoData) data;
     85         int originRotation = imageData.getRotation();
     86         int finalRotationDegrees;
     87         if (mClockwise) {
     88             finalRotationDegrees = (originRotation + 90) % 360;
     89         } else {
     90             finalRotationDegrees = (originRotation + 270) % 360;
     91         }
     92 
     93         String filePath = imageData.getPath();
     94         ContentValues values = new ContentValues();
     95         boolean success = false;
     96         int newOrientation = 0;
     97         if (imageData.getMimeType().equalsIgnoreCase(LocalData.MIME_TYPE_JPEG)) {
     98             ExifInterface exifInterface = new ExifInterface();
     99             ExifTag tag = exifInterface.buildTag(
    100                     ExifInterface.TAG_ORIENTATION,
    101                     ExifInterface.getOrientationValueForRotation(
    102                             finalRotationDegrees));
    103             if (tag != null) {
    104                 exifInterface.setTag(tag);
    105                 try {
    106                     // Note: This only works if the file already has some EXIF.
    107                     exifInterface.forceRewriteExif(filePath);
    108                     long fileSize = new File(filePath).length();
    109                     values.put(Images.Media.SIZE, fileSize);
    110                     newOrientation = finalRotationDegrees;
    111                     success = true;
    112                 } catch (FileNotFoundException e) {
    113                     Log.w(TAG, "Cannot find file to set exif: " + filePath);
    114                 } catch (IOException e) {
    115                     Log.w(TAG, "Cannot set exif data: " + filePath);
    116                 }
    117             } else {
    118                 Log.w(TAG, "Cannot build tag: " + ExifInterface.TAG_ORIENTATION);
    119             }
    120         }
    121 
    122         PhotoData result = null;
    123         if (success) {
    124             // MediaStore using SQLite is thread safe.
    125             values.put(Images.Media.ORIENTATION, finalRotationDegrees);
    126             mContext.getContentResolver().update(imageData.getUri(),
    127                     values, null, null);
    128             double[] latLong = data.getLatLong();
    129             double latitude = 0;
    130             double longitude = 0;
    131             if (latLong != null) {
    132                 latitude = latLong[0];
    133                 longitude = latLong[1];
    134             }
    135 
    136             result = new PhotoData(data.getContentId(), data.getTitle(),
    137                     data.getMimeType(), data.getDateTaken(), data.getDateModified(),
    138                     data.getPath(), newOrientation, imageData.getWidth(),
    139                     imageData.getHeight(), data.getSizeInBytes(), latitude, longitude);
    140         }
    141 
    142         return result;
    143     }
    144 
    145     @Override
    146     protected void onPostExecute(LocalData result) {
    147         mProgress.dismiss();
    148         if (result != null) {
    149             mAdapter.updateData(mCurrentDataId, result);
    150         }
    151     }
    152 }
    153