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