blob: 8ac9a943c601940428baa8bbe3848c3181660131 [file] [log] [blame]
Angus Kong2bca2102014-03-11 16:27:30 -07001/*
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
17package com.android.camera.data;
18
19import android.app.ProgressDialog;
20import android.content.ContentValues;
21import android.content.Context;
22import android.os.AsyncTask;
23import android.provider.MediaStore.Images;
24
25import com.android.camera.data.LocalMediaData.PhotoData;
26import com.android.camera.debug.Log;
27import com.android.camera.exif.ExifInterface;
28import com.android.camera.exif.ExifTag;
29import com.android.camera2.R;
30
31import java.io.File;
32import java.io.FileNotFoundException;
33import 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 */
39public 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}