18ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde/* 28ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * Copyright (C) 2013 The Android Open Source Project 38ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * 48ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * Licensed under the Apache License, Version 2.0 (the "License"); 58ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * you may not use this file except in compliance with the License. 68ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * You may obtain a copy of the License at 78ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * 88ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * http://www.apache.org/licenses/LICENSE-2.0 98ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * 108ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * Unless required by applicable law or agreed to in writing, software 118ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * distributed under the License is distributed on an "AS IS" BASIS, 128ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * See the License for the specific language governing permissions and 148ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * limitations under the License. 158ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde */ 168ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 178ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohdepackage com.android.camera.data; 188ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 198ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohdeimport android.content.Context; 208ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohdeimport android.view.View; 218ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 228ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohdeimport com.android.camera.Storage; 238ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohdeimport com.android.camera.debug.Log; 2451cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newbergerimport com.android.camera.util.Size; 258ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohdeimport com.bumptech.glide.Glide; 266ce2f41ca6338c8b0055d1e79bc61a434ba91006Alan Newbergerimport com.bumptech.glide.load.Key; 276ce2f41ca6338c8b0055d1e79bc61a434ba91006Alan Newbergerimport com.bumptech.glide.signature.MediaStoreSignature; 288ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohdeimport com.google.common.base.Optional; 298ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 308ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohdeimport java.io.File; 318ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohdeimport java.text.DateFormat; 328ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 3377d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohdeimport javax.annotation.Nonnull; 3477d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 358ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde/** 368ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * A base class for all the local media files. The bitmap is loaded in 378ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * background thread. Subclasses should implement their own background loading 388ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * thread by sub-classing BitmapLoadTask and overriding doInBackground() to 398ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde * return a bitmap. 408ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde */ 418ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohdepublic abstract class FilmstripItemBase<T extends FilmstripItemData> implements FilmstripItem { 428ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde /** The minimum id to use to query for all media at a given media store uri */ 438ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public static final int QUERY_ALL_MEDIA_ID = -1; 448ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 458ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde protected final Context mContext; 4677d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde protected final GlideFilmstripManager mGlideManager; 478ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde protected final T mData; 488ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde protected final Metadata mMetaData; 498ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde protected final FilmstripItemAttributes mAttributes; 508ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde protected final DateFormat mDateFormatter = DateFormat.getDateTimeInstance(); 518ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 52689348be49bf1e5e5f705d55915f87292d9506edPaul Rohde protected Size mSuggestedSize; 5377d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 5477d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde public FilmstripItemBase(Context context, GlideFilmstripManager glideManager, T data, 5577d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde FilmstripItemAttributes attributes) { 568ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mContext = context; 5777d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde mGlideManager = glideManager; 588ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mData = data; 598ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mAttributes = attributes; 6077d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 618ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mMetaData = new Metadata(); 6277d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde 63689348be49bf1e5e5f705d55915f87292d9506edPaul Rohde mSuggestedSize = GlideFilmstripManager.TINY_THUMB_SIZE; 648ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 658ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 668ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde @Override 678ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public FilmstripItemData getData() { 688ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return mData; 698ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 708ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 718ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde @Override 728ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public boolean delete() { 738ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde File fileToDelete = new File(mData.getFilePath()); 748ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde boolean deletionSucceeded = fileToDelete.delete(); 758ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde deleteIfEmptyCameraSubDir(fileToDelete.getParentFile()); 768ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return deletionSucceeded; 778ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 788ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 798ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde @Override 8077d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde public void setSuggestedSize(int widthPx, int heightPx) { 8177d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde if (widthPx > 0 && heightPx > 0) { 82689348be49bf1e5e5f705d55915f87292d9506edPaul Rohde mSuggestedSize = new Size(widthPx, heightPx); 8377d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde } else { 8477d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde Log.w(TAG, "Suggested size was set to a zero area value!"); 8577d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde } 868ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 878ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 888ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde @Override 8977d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde public void recycle(@Nonnull View view) { 9077d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde Glide.clear(view); 9177d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde } 928ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 938ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde @Override 948ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public Optional<MediaDetails> getMediaDetails() { 958ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde MediaDetails mediaDetails = new MediaDetails(); 968ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mediaDetails.addDetail(MediaDetails.INDEX_TITLE, mData.getTitle()); 9751cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger mediaDetails.addDetail(MediaDetails.INDEX_WIDTH, getDimensions().getWidth()); 9851cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger mediaDetails.addDetail(MediaDetails.INDEX_HEIGHT, getDimensions().getHeight()); 998ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mediaDetails.addDetail(MediaDetails.INDEX_PATH, mData.getFilePath()); 1008ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mediaDetails.addDetail(MediaDetails.INDEX_DATETIME, 1018ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mDateFormatter.format(mData.getLastModifiedDate())); 1028ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde long mSizeInBytes = mData.getSizeInBytes(); 1038ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (mSizeInBytes > 0) { 1048ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mediaDetails.addDetail(MediaDetails.INDEX_SIZE, mSizeInBytes); 1058ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 1068ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 1078ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde Location location = mData.getLocation(); 1088ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (location != Location.UNKNOWN) { 1098ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde mediaDetails.addDetail(MediaDetails.INDEX_LOCATION, location.getLocationString()); 1108ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 1118ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return Optional.of(mediaDetails); 1128ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 1138ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 1148ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde @Override 1158ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public FilmstripItemAttributes getAttributes() { 1168ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return mAttributes; 1178ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 1188ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 1198ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde @Override 1208ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde public Metadata getMetadata() { 1218ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return mMetaData; 1228ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 1238ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 12451cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger @Override 12551cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger public Size getDimensions() { 12651cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger return mData.getDimensions(); 12751cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger } 12851cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger 12951cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger @Override 13051cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger public int getOrientation() { 13151cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger return mData.getOrientation(); 13251cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger } 13351cafa0a35546a42c573357aa7a031a79cf9ba1bAlan Newberger 13477d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde protected final Key generateSignature(FilmstripItemData data) { 1356ce2f41ca6338c8b0055d1e79bc61a434ba91006Alan Newberger // Per Glide docs, make default mime type be the empty String 13677d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde String mimeType = (data.getMimeType() == null) ? "" : data.getMimeType(); 13777d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde long modTimeSeconds = (data.getLastModifiedDate() == null) ? 0 : 13877d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde data.getLastModifiedDate().getTime() / 1000; 13977d9f023e76816e5da7bd067ad46cc0e9c98623fPaul Rohde return new MediaStoreSignature(mimeType, modTimeSeconds, data.getOrientation()); 1408ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 1418ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 1428ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde private void deleteIfEmptyCameraSubDir(File directory) { 1438ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // Make sure 'directory' refers to a valid existing empty directory. 1448ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (!directory.exists() || !directory.isDirectory() || directory.list().length != 0) { 1458ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde return; 1468ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 1478ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 1488ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // Check if this is a 'Camera' sub-directory. 1498ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde String cameraPathStr = Storage.DIRECTORY_FILE.getAbsolutePath(); 1508ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde String fileParentPathStr = directory.getParentFile().getAbsolutePath(); 1518ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde Log.d(TAG, "CameraPathStr: " + cameraPathStr + " fileParentPathStr: " + fileParentPathStr); 1528ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde 1538ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // Delete the directory if it's an empty sub-directory of the Camera 1548ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde // directory. 1558ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if (fileParentPathStr.equals(cameraPathStr)) { 1568ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde if(!directory.delete()) { 1578ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde Log.d(TAG, "Failed to delete: " + directory); 1588ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 1598ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 1608ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde } 1618ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohde} 162