blob: 445046182406ceb8de2d35e7c498da1f3a946a48 [file] [log] [blame]
Angus Kong49b9ba22013-05-13 13:42:21 -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.content.ContentResolver;
20import android.content.Context;
21import android.database.Cursor;
Angus Kong49b9ba22013-05-13 13:42:21 -070022import android.graphics.drawable.Drawable;
Angus Kong885367c2013-05-31 16:30:32 -070023import android.net.Uri;
Angus Kong49b9ba22013-05-13 13:42:21 -070024import android.os.AsyncTask;
25import android.provider.MediaStore;
Angus Kong49b9ba22013-05-13 13:42:21 -070026import android.util.Log;
27import android.view.View;
Angus Kong49b9ba22013-05-13 13:42:21 -070028
29import com.android.camera.Storage;
30import com.android.camera.ui.FilmStripView;
31import com.android.camera.ui.FilmStripView.ImageData;
32
33import java.util.ArrayList;
34import java.util.Collections;
Angus Kong885367c2013-05-31 16:30:32 -070035import java.util.Comparator;
Angus Kong49b9ba22013-05-13 13:42:21 -070036import java.util.List;
37
38/**
Angus Kong750e8ec2013-05-06 10:42:28 -070039 * A FilmStrip.DataProvider that provide data in the camera folder.
Angus Kong49b9ba22013-05-13 13:42:21 -070040 *
41 * The given view for camera preview won't be added until the preview info
42 * has been set by setCameraPreviewInfo(int, int).
43 */
44public class CameraDataAdapter implements FilmStripView.DataAdapter {
45 private static final String TAG = CameraDataAdapter.class.getSimpleName();
46
47 private static final int DEFAULT_DECODE_SIZE = 3000;
48 private static final String[] CAMERA_PATH = { Storage.DIRECTORY + "%" };
49
50 private List<LocalData> mImages;
51
52 private Listener mListener;
53 private View mCameraPreviewView;
54 private Drawable mPlaceHolder;
55
56 private int mSuggestedWidth = DEFAULT_DECODE_SIZE;
57 private int mSuggestedHeight = DEFAULT_DECODE_SIZE;
58
59 public CameraDataAdapter(Drawable placeHolder) {
60 mPlaceHolder = placeHolder;
61 }
62
63 public void setCameraPreviewInfo(View cameraPreview, int width, int height) {
64 mCameraPreviewView = cameraPreview;
65 addOrReplaceCameraData(buildCameraImageData(width, height));
66 }
67
68 public void requestLoad(ContentResolver resolver) {
69 QueryTask qtask = new QueryTask();
70 qtask.execute(resolver);
71 }
72
73 @Override
74 public int getTotalNumber() {
Angus Kong750e8ec2013-05-06 10:42:28 -070075 if (mImages == null) {
76 return 0;
77 }
Angus Kong49b9ba22013-05-13 13:42:21 -070078 return mImages.size();
79 }
80
81 @Override
82 public ImageData getImageData(int id) {
Angus Kong750e8ec2013-05-06 10:42:28 -070083 if (mImages == null || id >= mImages.size() || id < 0) {
84 return null;
85 }
Angus Kong49b9ba22013-05-13 13:42:21 -070086 return mImages.get(id);
87 }
88
89 @Override
Angus Kong750e8ec2013-05-06 10:42:28 -070090 public void suggestDecodeSize(int w, int h) {
Angus Kong49b9ba22013-05-13 13:42:21 -070091 if (w <= 0 || h <= 0) {
92 mSuggestedWidth = mSuggestedHeight = DEFAULT_DECODE_SIZE;
93 } else {
94 mSuggestedWidth = (w < DEFAULT_DECODE_SIZE ? w : DEFAULT_DECODE_SIZE);
95 mSuggestedHeight = (h < DEFAULT_DECODE_SIZE ? h : DEFAULT_DECODE_SIZE);
96 }
97 }
98
99 @Override
100 public View getView(Context c, int dataID) {
Angus Kong750e8ec2013-05-06 10:42:28 -0700101 if (mImages == null) {
102 return null;
103 }
Angus Kong49b9ba22013-05-13 13:42:21 -0700104 if (dataID >= mImages.size() || dataID < 0) {
105 return null;
106 }
107
108 return mImages.get(dataID).getView(
Angus Kongaccc6e52013-05-30 15:53:37 -0700109 c, mSuggestedWidth, mSuggestedHeight,
110 mPlaceHolder.getConstantState().newDrawable());
Angus Kong49b9ba22013-05-13 13:42:21 -0700111 }
112
113 @Override
114 public void setListener(Listener listener) {
115 mListener = listener;
Angus Kong750e8ec2013-05-06 10:42:28 -0700116 if (mImages != null) {
117 mListener.onDataLoaded();
118 }
Angus Kong49b9ba22013-05-13 13:42:21 -0700119 }
120
Angus Kong87f9a622013-05-16 16:59:39 -0700121 public void removeData(int dataID) {
122 if (dataID >= mImages.size()) return;
123 LocalData d = mImages.remove(dataID);
124 mListener.onDataRemoved(dataID, d);
125 }
126
Angus Kong885367c2013-05-31 16:30:32 -0700127 private void insertData(LocalData data) {
128 if (mImages == null) {
129 mImages = new ArrayList<LocalData>();
130 }
131
132 // Since this function is mostly for adding the newest data,
133 // a simple linear search should yield the best performance over a
134 // binary search.
135 int pos = 0;
136 Comparator<LocalData> comp = new LocalData.NewestFirstComparator();
137 for (; pos < mImages.size()
138 && comp.compare(data, mImages.get(pos)) > 0; pos++);
139 mImages.add(pos, data);
140 if (mListener != null) {
141 mListener.onDataInserted(pos, data);
142 }
143 }
144
145 public void addNewVideo(ContentResolver cr, Uri uri) {
146 Cursor c = cr.query(uri,
147 LocalData.Video.QUERY_PROJECTION,
148 MediaStore.Images.Media.DATA + " like ? ", CAMERA_PATH,
149 LocalData.Video.QUERY_ORDER);
150 if (c != null && c.moveToFirst()) {
151 insertData(LocalData.Video.buildFromCursor(c));
152 }
153 }
154
155 public void addNewPhoto(ContentResolver cr, Uri uri) {
156 Cursor c = cr.query(uri,
157 LocalData.Photo.QUERY_PROJECTION,
158 MediaStore.Images.Media.DATA + " like ? ", CAMERA_PATH,
159 LocalData.Photo.QUERY_ORDER);
160 if (c != null && c.moveToFirst()) {
161 insertData(LocalData.Photo.buildFromCursor(c));
162 }
163 }
164
Angus Konga06b4e22013-06-03 11:10:11 -0700165 // Update all the data but keep the camera data if already set.
166 private void replaceData(List<LocalData> list) {
167 boolean changed = (list != mImages);
168 LocalData cameraData = null;
169 if (mImages != null && mImages.size() > 0) {
170 cameraData = mImages.get(0);
171 if (cameraData.getType() != ImageData.TYPE_CAMERA_PREVIEW) {
172 cameraData = null;
173 }
174 }
175
176 mImages = list;
177 if (cameraData != null) {
178 // camera view exists, so we make sure at least 1 data is in the list.
179 if (mImages == null) {
180 mImages = new ArrayList<LocalData>();
181 }
182 mImages.add(0, cameraData);
183 if (mListener != null) {
184 // Only the camera data is not changed, everything else is changed.
185 mListener.onDataUpdated(new UpdateReporter() {
186 @Override
187 public boolean isDataRemoved(int id) {
188 return false;
189 }
190
191 @Override
192 public boolean isDataUpdated(int id) {
193 if (id == 0) return false;
194 return true;
195 }
196 });
197 }
198 } else {
199 // both might be null.
200 if (changed) {
201 mListener.onDataLoaded();
202 }
203 }
204 }
205
206 public void flush() {
207 replaceData(null);
208 }
209
210 public void addLocalData(LocalData data) {
211 insertData(data);
212 }
213
Angus Kong49b9ba22013-05-13 13:42:21 -0700214 private LocalData buildCameraImageData(int width, int height) {
215 LocalData d = new CameraPreviewData(width, height);
216 return d;
217 }
218
219 private void addOrReplaceCameraData(LocalData data) {
Angus Kong750e8ec2013-05-06 10:42:28 -0700220 if (mImages == null) {
221 mImages = new ArrayList<LocalData>();
222 }
Angus Kong49b9ba22013-05-13 13:42:21 -0700223 if (mImages.size() == 0) {
224 // No data at all.
225 mImages.add(0, data);
Angus Kong750e8ec2013-05-06 10:42:28 -0700226 if (mListener != null) {
227 mListener.onDataLoaded();
228 }
Angus Kong49b9ba22013-05-13 13:42:21 -0700229 return;
230 }
231
232 LocalData first = mImages.get(0);
233 if (first.getType() == ImageData.TYPE_CAMERA_PREVIEW) {
234 // Replace the old camera data.
235 mImages.set(0, data);
236 if (mListener != null) {
237 mListener.onDataUpdated(new UpdateReporter() {
238 @Override
239 public boolean isDataRemoved(int id) {
240 return false;
241 }
242
243 @Override
244 public boolean isDataUpdated(int id) {
Angus Kong750e8ec2013-05-06 10:42:28 -0700245 if (id == 0) {
246 return true;
247 }
Angus Kong49b9ba22013-05-13 13:42:21 -0700248 return false;
249 }
250 });
251 }
252 } else {
253 // Add a new camera data.
254 mImages.add(0, data);
255 if (mListener != null) {
256 mListener.onDataLoaded();
257 }
258 }
259 }
260
261 private class QueryTask extends AsyncTask<ContentResolver, Void, List<LocalData>> {
262 @Override
263 protected List<LocalData> doInBackground(ContentResolver... resolver) {
264 List<LocalData> l = new ArrayList<LocalData>();
265 // Photos
266 Cursor c = resolver[0].query(
Angus Kongb40738a2013-06-03 14:55:34 -0700267 LocalData.Photo.CONTENT_URI,
Angus Kong750e8ec2013-05-06 10:42:28 -0700268 LocalData.Photo.QUERY_PROJECTION,
Angus Kong49b9ba22013-05-13 13:42:21 -0700269 MediaStore.Images.Media.DATA + " like ? ", CAMERA_PATH,
Angus Kong750e8ec2013-05-06 10:42:28 -0700270 LocalData.Photo.QUERY_ORDER);
Angus Kong49b9ba22013-05-13 13:42:21 -0700271 if (c != null && c.moveToFirst()) {
272 // build up the list.
273 while (true) {
Angus Kong750e8ec2013-05-06 10:42:28 -0700274 LocalData data = LocalData.Photo.buildFromCursor(c);
Angus Kong49b9ba22013-05-13 13:42:21 -0700275 if (data != null) {
276 l.add(data);
277 } else {
278 Log.e(TAG, "Error loading data:"
Angus Kong750e8ec2013-05-06 10:42:28 -0700279 + c.getString(LocalData.Photo.COL_DATA));
Angus Kong49b9ba22013-05-13 13:42:21 -0700280 }
Angus Kong750e8ec2013-05-06 10:42:28 -0700281 if (c.isLast()) {
282 break;
283 }
Angus Kong49b9ba22013-05-13 13:42:21 -0700284 c.moveToNext();
285 }
286 }
Angus Kong750e8ec2013-05-06 10:42:28 -0700287 if (c != null) {
288 c.close();
289 }
Angus Kong49b9ba22013-05-13 13:42:21 -0700290
291 c = resolver[0].query(
Angus Kongb40738a2013-06-03 14:55:34 -0700292 LocalData.Video.CONTENT_URI,
Angus Kong750e8ec2013-05-06 10:42:28 -0700293 LocalData.Video.QUERY_PROJECTION,
Angus Kong49b9ba22013-05-13 13:42:21 -0700294 MediaStore.Video.Media.DATA + " like ? ", CAMERA_PATH,
Angus Kong750e8ec2013-05-06 10:42:28 -0700295 LocalData.Video.QUERY_ORDER);
Angus Kong49b9ba22013-05-13 13:42:21 -0700296 if (c != null && c.moveToFirst()) {
297 // build up the list.
298 c.moveToFirst();
299 while (true) {
Angus Kong750e8ec2013-05-06 10:42:28 -0700300 LocalData data = LocalData.Video.buildFromCursor(c);
Angus Kong49b9ba22013-05-13 13:42:21 -0700301 if (data != null) {
302 l.add(data);
303 Log.v(TAG, "video data added:" + data);
304 } else {
305 Log.e(TAG, "Error loading data:"
Angus Kong750e8ec2013-05-06 10:42:28 -0700306 + c.getString(LocalData.Video.COL_DATA));
Angus Kong49b9ba22013-05-13 13:42:21 -0700307 }
Angus Kong750e8ec2013-05-06 10:42:28 -0700308 if (!c.isLast()) {
309 c.moveToNext();
310 } else {
311 break;
312 }
Angus Kong49b9ba22013-05-13 13:42:21 -0700313 }
314 }
Angus Kong750e8ec2013-05-06 10:42:28 -0700315 if (c != null) {
316 c.close();
317 }
Angus Kong49b9ba22013-05-13 13:42:21 -0700318
319 if (l.size() == 0) return null;
320
Angus Kong750e8ec2013-05-06 10:42:28 -0700321 Collections.sort(l, new LocalData.NewestFirstComparator());
Angus Kong49b9ba22013-05-13 13:42:21 -0700322 return l;
323 }
324
325 @Override
326 protected void onPostExecute(List<LocalData> l) {
Angus Konga06b4e22013-06-03 11:10:11 -0700327 replaceData(l);
Angus Kong49b9ba22013-05-13 13:42:21 -0700328 }
329 }
330
Angus Kong750e8ec2013-05-06 10:42:28 -0700331 private class CameraPreviewData implements LocalData {
332 private int width;
333 private int height;
Angus Kong49b9ba22013-05-13 13:42:21 -0700334
Angus Kong49b9ba22013-05-13 13:42:21 -0700335 CameraPreviewData(int w, int h) {
336 width = w;
337 height = h;
338 }
339
340 @Override
Angus Kong750e8ec2013-05-06 10:42:28 -0700341 public long getDateTaken() {
342 // This value is used for sorting.
343 return -1;
344 }
345
346 @Override
347 public long getDateModified() {
348 // This value might be used for sorting.
349 return -1;
350 }
351
352 @Override
353 public String getTitle() {
354 return "";
355 }
356
357 @Override
Angus Kong49b9ba22013-05-13 13:42:21 -0700358 public int getWidth() {
359 return width;
360 }
361
362 @Override
363 public int getHeight() {
364 return height;
365 }
366
367 @Override
368 public int getType() {
369 return ImageData.TYPE_CAMERA_PREVIEW;
370 }
371
372 @Override
Angus Kong750e8ec2013-05-06 10:42:28 -0700373 public boolean isActionSupported(int action) {
374 return false;
375 }
376
377 @Override
378 public View getView(Context c, int width, int height, Drawable placeHolder) {
Angus Kong49b9ba22013-05-13 13:42:21 -0700379 return mCameraPreviewView;
380 }
Angus Kong49b9ba22013-05-13 13:42:21 -0700381
Angus Kong750e8ec2013-05-06 10:42:28 -0700382 @Override
383 public void prepare() {
384 // do nothing.
Angus Kong49b9ba22013-05-13 13:42:21 -0700385 }
386
387 @Override
Angus Kong750e8ec2013-05-06 10:42:28 -0700388 public void recycle() {
389 // do nothing.
Angus Kong49b9ba22013-05-13 13:42:21 -0700390 }
391 }
Angus Kong49b9ba22013-05-13 13:42:21 -0700392}